Files.walk.filter和Files.find有什么区别?

8

这段代码用于搜索特定文件:

Stream<Path> findMyFile = Files.find(Paths.get("c:\\temp\\pathtest"), Integer.MAX_VALUE,(p, a) -> p.endsWith("test.txt") && a.isRegularFile());

Stream<Path> findMyFileSecond = Files.walk(Paths.get("c:\\temp\\pathtest"),Integer.MAX_VALUE).filter(p -> p.endsWith("test.txt"));

findMyFile.forEach(System.out::println);
findMyFileSecond.forEach(System.out::println);

两种方法都包含相同的文件,并且两种方法完成时间几乎相同。JavaDoc中如下所述:
此方法按照#walk walk方法指定的方式精确地遍历文件树。与调用java.util.stream.Stream#filter Stream上的filter不同,通过{@code walk}方法返回的此方法可以通过避免冗余检索BasicFileAttributes而更加高效。
何时应该将walkfilter组合使用,何时使用find?什么被认为是最佳实践?

1
文档非常清晰。如果您只打算对walk返回的流应用过滤器,则findwalk更好。 - VGR
2个回答

9

简而言之:如果你需要按属性过滤出文件/目录,请使用Files.find(),如果你不需要按文件属性过滤,请使用Files.walk()

详情

实际上有一个细微的差别,这在文档中已经解释过,但是解释方式让人感觉完全错误。阅读源代码可以澄清这一点:

  • Files.find:

    return StreamSupport.stream(...)
                            .onClose(iterator::close)
                            .filter(entry -> matcher.test(entry.file(), entry.attributes()))
                            .map(entry -> entry.file());
    
  • Files.walk:

    return StreamSupport.stream(...)
                            .onClose(iterator::close)
                            .map(entry -> entry.file());
    
这意味着,如果在最终筛选中,您需要获取并验证文件属性,那么File.find的速度可能会更快。这是因为对于File.walk,您的筛选回调需要额外调用例如Files.readAttributes(file, BasicFileAttributes.class),而对于File.find,属性已经被检索并在筛选回调中提供给您。我刚刚在Windows上使用我的样本结构(包含许多文件夹中的10K个文件)进行了测试,仅搜索文件(即不包括文件夹)。
// pre-Java7/8 way via recursive listFiles (8037 files returned): 1521.657 msec.
for (File f : new File(dir).listFiles()) {
    if (f.isDirectory()) {
        _getFiles(files, path, pattern);
    } else {
        ...
    }
}

// Files.walk(8037 files returned): 1575.766823 msec.
try (Stream<Path> stream = Files.walk(path, Integer.MAX_VALUE) {
    files = stream.filter(p -> {
        if (Files.isDirectory(p)) { return false; } // this extra check makes it much slower than Files.find
        ... 
    }).map(p -> p.toString()).collect(Collectors.toList());
}

// Files.find(8037 files returned): 27.606675 msec.
try (Stream<Path> stream = Files.find(path, Integer.MAX_VALUE, (p, a) -> !a.isDirectory())) {
    files = stream.filter(p -> { ... }).map(p -> p.toString()).collect(Collectors.toList());
}

// Files.walkFileTree(8037 returned): 27.443974 msec.
Files.walkFileTree(new File(path).toPath(), new SimpleFileVisitor<Path>() { 
    @Override
    public FileVisitResult visitFile(Path p, BasicFileAttributes attrs) throws IOException {
        ...
        return FileVisitResult.CONTINUE;
    }
});

1
很好,BasicFileAttributes有它们的用途,例如isRegularFile、lastModifiedTime等。 - Joop Eggen

1
我认为如果您需要在应用过滤器或并行流之前对目录列表进行某些中间操作,walk()会很有优势。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接