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

标签 java file path nio2

此代码搜索特定文件:

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 说明如下:

This method walks the file tree in exactly the manner specified by * the #walk walk method Compare to calling * java.util.stream.Stream#filter filter on the Stream * returned by {@code walk} method, this meth od may be more efficient by * avoiding redundant retrieval of the BasicFileAttributes

什么时候应该将 walkfilter 结合使用,什么时候应该使用 find?什么是最佳实践?

最佳答案

TL;DR:如果您需要按属性过滤掉文件/目录 - 使用 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-files-in-many-folders 结构对其进行了测试:

// 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;
    }
});

关于java - Files.walk.filter 和 Files.find 有什么区别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42253688/

相关文章:

path - SVG:简化删除曲线的路径?

java - 在哪里可以找到 org.omg.CosTransactions 包

Java - 如何处理动态 JSON 类别名称?

java - eclipse默认的jpa实现库哪里下载?

java - Android应用程序已停止,无法理解错误日志

ruby - "file.sync = true"是做什么的?

php - 在数据库中存储文件的优点和缺点是什么?

ruby-on-rails - 如何在 Ruby on Rails 中解压缩文件?

javascript - 使用 FabricJS 进行图像剪辑到路径

node.js - NodeJS : what is difference between "./.." and ".." in require?