我如何递归地列出在Java目录下的所有文件?框架是否提供任何实用程序?

我看到了很多俗气的实现。但没有来自框架或nio


当前回答

对于这种简单的转换,我更喜欢使用队列而不是递归:

List<File> allFiles = new ArrayList<File>();
Queue<File> dirs = new LinkedList<File>();
dirs.add(new File("/start/dir/"));
while (!dirs.isEmpty()) {
  for (File f : dirs.poll().listFiles()) {
    if (f.isDirectory()) {
      dirs.add(f);
    } else if (f.isFile()) {
      allFiles.add(f);
    }
  }
}

其他回答

Java 8提供了一个很好的流来处理树中的所有文件。

try (Stream<Path> stream = Files.walk(Paths.get(path))) {
    stream.filter(Files::isRegularFile)
          .forEach(System.out::println);
}

这提供了一种自然的遍历文件的方法。因为它是一个流,你可以对结果做所有漂亮的流操作,如限制,分组,映射,退出等。

更新:我可能会指出还有文件。find使用一个BiPredicate,如果需要检查文件属性,这可能更有效。

Files.find(Paths.get(path),
           Integer.MAX_VALUE,
           (filePath, fileAttr) -> fileAttr.isRegularFile())
        .forEach(System.out::println);

注意,虽然JavaDoc回避了这个方法可能比Files更有效。Walk实际上是相同的,如果您也在过滤器中检索文件属性,则可以观察到性能上的差异。最后,如果需要筛选属性,请使用Files。find,否则使用Files。步行,主要是因为交通超载,而且更方便。

测试:根据要求,我提供了许多答案的性能比较。查看包含结果和测试用例的Github项目。

在Java 8中,我们现在可以使用Files实用程序遍历文件树。非常简单。

Files.walk(root.toPath())
      .filter(path -> !Files.isDirectory(path))
      .forEach(path -> System.out.println(path));

对于这种简单的转换,我更喜欢使用队列而不是递归:

List<File> allFiles = new ArrayList<File>();
Queue<File> dirs = new LinkedList<File>();
dirs.add(new File("/start/dir/"));
while (!dirs.isEmpty()) {
  for (File f : dirs.poll().listFiles()) {
    if (f.isDirectory()) {
      dirs.add(f);
    } else if (f.isFile()) {
      allFiles.add(f);
    }
  }
}

即使有人已经提供了Java 8 walk,您也可以这样做。

它将递归地为您提供所有文件

  private Stream<File> files(File file) {
    return file.isDirectory()
            ? Arrays.stream(file.listFiles()).flatMap(this::files)
            : Stream.of(file);
}
    private void fillFilesRecursively(File file, List<File> resultFiles) {
        if (file.isFile()) {
            resultFiles.add(file);
        } else {
            for (File child : file.listFiles()) {
                fillFilesRecursively(child, resultFiles);
            }
        }
    }