使用Java计算目录中的文件数

使用Java计算目录中的文件数,java,performance,file,directory,Java,Performance,File,Directory,如何使用Java计算目录中的文件数?为简单起见,假设该目录没有任何子目录 我知道以下的标准方法: new File(<directory path>).listFiles().length new File().listFiles().length 但这将有效地遍历目录中的所有文件,如果文件数量很大,这可能需要很长时间。此外,我不关心目录中的实际文件,除非它们的数量大于某个固定的大数字(比如5000) 我猜,但目录(或Unix中的I节点)不存储其中包含的文件数吗?如果我能直接从文

如何使用Java计算目录中的文件数?为简单起见,假设该目录没有任何子目录

我知道以下的标准方法:

new File(<directory path>).listFiles().length
new File().listFiles().length
但这将有效地遍历目录中的所有文件,如果文件数量很大,这可能需要很长时间。此外,我不关心目录中的实际文件,除非它们的数量大于某个固定的大数字(比如5000)

我猜,但目录(或Unix中的I节点)不存储其中包含的文件数吗?如果我能直接从文件系统中获取这个数字,速度会快得多。在后端开始真正的处理之前,我需要对Tomcat服务器上的每个HTTP请求进行检查。因此,速度至关重要


我可以每隔一段时间运行一次守护程序来清除目录。我知道这一点,所以请不要给我那个解决方案。

不幸的是,我相信这已经是最好的方法了(虽然比
listFiles()
稍微好一点,因为它不构造
文件
对象)。

啊。。。在Java中没有一个简单的方法来实现这一点的基本原理是文件存储抽象:一些文件系统可能没有一个目录中现成的文件数量。。。这个计数可能根本没有任何意义(例如,请参阅分布式、P2P文件系统、将文件列表存储为链接列表的fs,或数据库支持的文件系统…)。 所以是的

新建文件().list().length

可能是您最好的选择。

不幸的是,正如mmyers所说,File.list()的速度与您使用Java的速度差不多。如果速度和你说的一样重要,你可能想考虑使用这个特定的操作。然后,您可以根据您的特定情况和文件系统定制代码。

这可能不适合您的应用程序,但您可以始终尝试本机调用(使用jni或),或执行特定于平台的命令并读取输出,然后再返回到list().length。在*nix上,可以执行
ls-1a | wc-l
(注意:第一个命令是dash-one-a,第二个命令是dash-lowercase-l)。不确定windows上什么是正确的-可能只是一个
dir
,然后查找摘要

在处理类似的问题之前,我强烈建议您创建一个包含大量文件的目录,然后看看list().length是否真的需要太长的时间。正如建议的那样,您可能不想为此而烦恼


我自己可能会同意Varkhan的答案。

如果目录中包含的文件非常多(>100000),那么下面是一个(不可移植的)方法:

String directoryPath = "a path";

// -f flag is important, because this way ls does not sort it output,
// which is way faster
String[] params = { "/bin/sh", "-c",
    "ls -f " + directoryPath + " | wc -l" };
Process process = Runtime.getRuntime().exec(params);
BufferedReader reader = new BufferedReader(new InputStreamReader(
    process.getInputStream()));
String fileCount = reader.readLine().trim() - 2; // accounting for .. and .
reader.close();
System.out.println(fileCount);
使用sigar应该会有所帮助。有本机钩子来获取统计信息

new Sigar().getDirStat(dir).getTotal()

由于您实际上不需要总数,并且实际上希望在某个数字之后执行操作(在您的案例中为5000),因此可以使用。这样做的好处是,您可以提前退出,而不必遍历整个目录来获取计数

public boolean isOverMax(){
    Path dir = Paths.get("C:/foo/bar");
    int i = 1;

    try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir)) {
        for (Path p : stream) {
            //larger than max files, exit
            if (++i > MAX_FILES) {
                return true;
            }
        }
    } catch (IOException ex) {
        ex.printStackTrace();
    }

    return false;
}
public boolean isOverMax(){
Path dir=Path.get(“C:/foo/bar”);
int i=1;
try(DirectoryStream=Files.newDirectoryStream(dir)){
for(路径p:流){
//大于最大值的文件,退出
如果(++i>MAX_文件){
返回true;
}
}
}捕获(IOEX异常){
例如printStackTrace();
}
返回false;
}

for
DirectoryStream
也有一些很好的例子

自Java 8以来,您可以通过三行代码来完成:

try (Stream<Path> files = Files.list(Paths.get("your/path/here"))) {
    long count = files.count();
}
try(Stream files=files.list(path.get(“your/path/here”)){
长计数=files.count();
}
关于5000个子节点和inode方面:

此方法将迭代条目,但正如Varkhan所建议的,除了使用JNI或直接系统命令调用之外,您可能做得不好,但即使这样,您也无法确保这些方法不会做同样的事情

但是,让我们深入了解一下:

查看JDK8源代码,
Files.list
公开了一个流,该流使用来自
Files.newDirectoryStream的
Iterable
,该流委托给
FileSystemProvider.newDirectoryStream

在UNIX系统上(反编译的
sun.nio.fs.UnixFileSystemProvider.class
),它加载迭代器:使用
sun.nio.fs.UnixSecureDirectoryStream
(在目录中迭代时带有文件锁)

因此,这里有一个迭代器,它将循环遍历条目

现在,让我们看看计数机制

实际计数由暴露的计数/总和减少API执行。理论上,此API可以执行并行操作,而无需花费太多精力(使用multihtreading)。但是,流是在禁用并行性的情况下创建的,因此它是不可能的

这种方法的好的一面是它不会在内存中加载数组,因为在底层(文件系统)API读取条目时,迭代器会对条目进行计数


最后,对于信息,从概念上讲,在文件系统中,目录节点不需要保存它所包含的文件数,它可以只包含它的子节点列表(inode列表)。我不是文件系统方面的专家,但我相信UNIX文件系统就是这样工作的。因此,您不能假设有一种方法可以直接获取这些信息(即:总有一些子节点列表隐藏在某个地方)。

在spring批处理中,我做了如下操作

private int getFilesCount() throws IOException {
        ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        Resource[] resources = resolver.getResources("file:" + projectFilesFolder + "/**/input/splitFolder/*.csv");
        return resources.length;
    }

这个方法对我很有效

    // Recursive method to recover files and folders and to print the information
public static void listFiles(String directoryName) {

    File file = new File(directoryName);
    File[] fileList = file.listFiles(); // List files inside the main dir
    int j;
    String extension;
    String fileName;

    if (fileList != null) {
        for (int i = 0; i < fileList.length; i++) {
            extension = "";
            if (fileList[i].isFile()) {
                fileName = fileList[i].getName();

                if (fileName.lastIndexOf(".") != -1 && fileName.lastIndexOf(".") != 0) {
                    extension = fileName.substring(fileName.lastIndexOf(".") + 1);
                    System.out.println("THE " + fileName + "  has the extension =   " + extension);
                } else {
                    extension = "Unknown";
                    System.out.println("extension2 =    " + extension);
                }

                filesCount++;
                allStats.add(new FilePropBean(filesCount, fileList[i].getName(), fileList[i].length(), extension,
                        fileList[i].getParent()));
            } else if (fileList[i].isDirectory()) {
                filesCount++;
                extension = "";
                allStats.add(new FilePropBean(filesCount, fileList[i].getName(), fileList[i].length(), extension,
                        fileList[i].getParent()));
                listFiles(String.valueOf(fileList[i]));
            }
        }
    }
}
//恢复文件和文件夹并打印信息的递归方法
公共静态无效列表文件(字符串目录名){
文件=新文件(目录名);
File[]fileList=File.listFiles();//列出主目录中的文件
int j;
字符串扩展;
字符串文件名;
如果
private int getFilesCount() throws IOException {
        ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        Resource[] resources = resolver.getResources("file:" + projectFilesFolder + "/**/input/splitFolder/*.csv");
        return resources.length;
    }
    // Recursive method to recover files and folders and to print the information
public static void listFiles(String directoryName) {

    File file = new File(directoryName);
    File[] fileList = file.listFiles(); // List files inside the main dir
    int j;
    String extension;
    String fileName;

    if (fileList != null) {
        for (int i = 0; i < fileList.length; i++) {
            extension = "";
            if (fileList[i].isFile()) {
                fileName = fileList[i].getName();

                if (fileName.lastIndexOf(".") != -1 && fileName.lastIndexOf(".") != 0) {
                    extension = fileName.substring(fileName.lastIndexOf(".") + 1);
                    System.out.println("THE " + fileName + "  has the extension =   " + extension);
                } else {
                    extension = "Unknown";
                    System.out.println("extension2 =    " + extension);
                }

                filesCount++;
                allStats.add(new FilePropBean(filesCount, fileList[i].getName(), fileList[i].length(), extension,
                        fileList[i].getParent()));
            } else if (fileList[i].isDirectory()) {
                filesCount++;
                extension = "";
                allStats.add(new FilePropBean(filesCount, fileList[i].getName(), fileList[i].length(), extension,
                        fileList[i].getParent()));
                listFiles(String.valueOf(fileList[i]));
            }
        }
    }
}