我有一个简单的问题:我使用Files.walkFileTree
迭代一个大而深度嵌套的目录结构,如下所示:
final int CUTOFF = 5;
final List<Path> foundList = new ArrayList<>();
Files.walkFileTree( codeRoot, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs)
throws IOException {
String rPath = codeRoot.relativize( dir ).toString();
int level = rPath.length() - rPath.replace("/", "").length();
if (dir.getFileName().toString().equals( "target" ) || level < CUTOFF) {
return FileVisitResult.CONTINUE;
}
return FileVisitResult.SKIP_SUBTREE;
}
@Override
public FileVisitResult visitFile( Path file, BasicFileAttributes attrs )
throws IOException {
if (file.getFileName().toString().endsWith( ".txt" )) {
foundList.add( file );
}
return FileVisitResult.CONTINUE;
}
} );
我的目标是将所有文件添加到target
下我知道最多CUTOFF
级别的特定目录codeRoot
下。
我正在寻找一种更有效的方式来处理必要的stat()
电话或有人说'#34;无法完成&#34;。
语言级别是Java8。
答案 0 :(得分:1)
优化选项:
1)在目录更改时注册通知:https://docs.oracle.com/javase/tutorial/essential/io/notification.html 这可以在后台工作
2)(不太理想)使用未更改目录的缓存(在某些文件系统中):使用目录的最后修改时间来缓存自上次调用以来未发生变化的目录
使用grepcode,我找不到如何实现relativize,我认为它可能是本机实现的。我想它是通过已经拉动的值的简单字符串操作实现的,我不认为它正在访问stat()
。您可以测试它,但是,使用和不使用relativize
制作一个虚拟代码(它没有任何有用的功能),并在遍历大量文件时测量实际影响。由于relativize
答案 1 :(得分:1)
提出的算法是一次性查询。在这种情况下,您将陷入所有目录的线性时间搜索。您无法最大限度地减少检查每个目录的需要。当然,您可以查看缓存,但如果您打算使用缓存一致性并且需要高性能,那么您也可以考虑构建索引。在任何一种情况下,我都会解决您提出的问题,即一次性查询。
您正在使用的Files.walkFileTree
版本遍历整个树,包括超过最高级别的所有文件和目录。您通过解析路径名明确地排除它们,这是您认为可能效率不高的技术。解决方案是始终阅读文档。有Files.walkFileTree
的第二个版本,最大深度作为显式参数。来自tutorial on walking the file tree:
第二个walkFileTree方法允许您另外指定访问级别数和一组FileVisitOption枚举的限制。
如果你使用第二种方法,你只会访问最高级别的候选文件,你可以避免修剪子树的所有代码。