5

我有一个包含 50,000 个路径的列表,我需要检查每个路径是否存在文件。现在,我正在像这样独立验证每条路径:

public static List<String> filesExist(String baseDirectory, Iterable<String> paths) throws FileNotFoundException{
        File directory = new File(baseDirectory);
        if(!directory.exists()){
            throw new FileNotFoundException("No Directory found: " + baseDirectory );
        }else{
            if(!directory.isDirectory())
                throw new FileNotFoundException(baseDirectory + " is not a directory!");
        }

        List<String> filesNotFound = new ArrayList<String>();

        for (String path : paths) {
            if(!new File(baseDirectory + path).isFile())
                filesNotFound.add(path);
        }
        return filesNotFound;
    }

有没有办法改进它,这样我就不会创建 50,000 个文件对象?我也在用番石榴。那里有什么实用程序可以帮助我使用批量exists()方法吗?

4

5 回答 5

5

创建 50,000 个File对象几乎肯定不是瓶颈。实际的文件系统操作可能是让它变慢的原因。

我有两个建议:

  1. 在检查之前,按照路径的位置对路径进行排序,以充分利用文件系统缓存。
  2. 如果子目录不存在,您可以自动假设其中的所有文件和子目录也不存在。
于 2012-06-15T08:02:57.307 回答
0

我会为此使用特殊的数据结构。

特里

在此处输入图像描述

将您的终端节点视为包含文件夹的文件和父节点。您可以检查您的文件夹中的终端节点。如果某些文件共享相同的父文件,它将大大减少查找操作的数量。

你的总操作数将是

总运营 = 总节点 - 终端节点

简单的遍历算法你的特殊树就足够了。抱歉,但坚信此解决方案不是基于 Guava,但更适合。

于 2012-06-15T13:46:58.513 回答
0

我同意aix 的上一个回答,但我想补充一点。假设文件系统访问是瓶颈,并且如果baseDirectory 下的文件数量大致已知并且不太大(无论这意味着什么),那么可能值得尝试FileUtils.iterateFilesor FileUtils.listFiles,然后检查每个返回的路径是否存在于路径中。这背后的想法是,这些方法执行的目录列表可能比许多单独的访问更有效。

同样,这种方法取决于对您的环境的许多假设,但总是值得考虑并尝试一下。

(想将此作为评论添加到 aix 的回复中,但不能...)

于 2012-06-15T08:29:19.117 回答
0

恕我直言,一个非常有效的解决方案(受先前两个答案的启发)如下:

  • 对路径进行排序
  • 将它们中的每一个都视为树
  • 另一棵树是目录树
  • 访问目录树时读取整个目录,以防另一棵树中有“许多”子级,否则使用单独检查“少数”子级
  • 对两棵树进行并行遍历,跳过其中一棵树中缺少的部分

示例(作为预购列表给出的树):

tree1: / /a /a/a /d /d/a /d/a/b /e
tree2: / /a /b /d /d/a /e

加工:

  • 从...开始/
  • 下降到/a因为存在于两者中
  • 跳过/a/atree2中的缺失
  • 跳过/btree1 中的缺失
  • 下降到/d因为存在于两者中
  • ...

您的filesNotFound列表包含与输入列表对应的树中跳过的所有文件。

于 2012-06-15T09:15:07.463 回答
0

由于某些原因,我现在无法启动我的开发环境,所以这可能有点不正确。Go-go 小工具函数式编程!

public static List<String> filesExist(String baseDirectory, Iterable<String> paths) throws FileNotFoundException{
    final File base = new File(baseDirectory);
    if (base.exists()) {
        return FluentIterable.from(paths).filter(new Predicate<String>() {
            public boolean apply(String in) {
                return new File(in,base).exists();
            }
        }).toImmutableList();
    }
    throw new FileNotFoundException("Base doesn't exist!");
}

如上所述,您的主要问题仍然是 I/O。

于 2012-06-15T13:15:09.733 回答