在特定目录中找到文件

时间:2015-09-30 09:11:42

标签: java nio

我有一个简单的问题:我使用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。

2 个答案:

答案 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枚举的限制。

如果你使用第二种方法,你只会访问最高级别的候选文件,你可以避免修剪子树的所有代码。