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 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 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() {
@Override
public FileVisitResult visitFile(Path p, BasicFileAttributes attrs) throws IOException {
...
return FileVisitResult.CONTINUE;
}
});