更快地获取大型目录内容(java.io.File的替代方法)

16

我使用旧的、过时的java.io.File.listFiles()太久了。

性能不太好,因为:

  • 它是昂贵的,因为它为每个条目创建一个新的File对象。
  • 它很慢,因为你必须在处理之前等待数组完成。
  • 它非常糟糕,尤其是如果你只需要处理内容的子集。

有什么替代方案吗?

1个回答

31
Java 7的 java.nio.file 包可用于提高性能。

迭代器

可以使用 DirectoryStream<T> 接口在不将其内容预加载到内存中的情况下迭代目录。 旧的API会创建一个包含文件夹中所有文件名的数组,而新方法在迭代期间遇到每个文件名(或缓存文件名的有限大小组)时加载它。
要获取表示给定 Path 的实例,可以调用 Files.newDirectoryStream(Path) 静态方法。 我建议您使用 try-with-resources 语句来正确关闭流,但如果您无法这样做,请记得在最后手动关闭流,方法是 DirectoryStream<T>.close()
Path folder = Paths.get("...");
try (DirectoryStream<Path> stream = Files.newDirectoryStream(folder)) {
    for (Path entry : stream) {
        // Process the entry
    }
} catch (IOException ex) {
    // An I/O problem has occurred
}

筛选器

DirectoryStream.Filter<T>接口可用于在迭代期间跳过一组条目。

由于它是@FunctionalInterface,因此从Java 8开始,您可以使用lambda表达式来实现它,重写决定是否接受或过滤给定目录条目的Filter<T>.accept(T)方法。然后,您将使用新创建的实例和Files.newDirectoryStream(Path, DirectoryStream.Filter<? super Path>)静态方法。

或者,您可能更喜欢使用Files.newDirectoryStream(Path, String)静态方法进行简单的文件名匹配。

Path folder = Paths.get("...");
try (DirectoryStream<Path> stream = Files.newDirectoryStream(folder, "*.txt")) {
    for (Path entry : stream) {
        // The entry can only be a text file
    }
} catch (IOException ex) {
    // An I/O problem has occurred
}

Path folder = Paths.get("...");
try (DirectoryStream<Path> stream = Files.newDirectoryStream(folder,
        entry -> Files.isDirectory(entry))) {
    for (Path entry : stream) {
        // The entry can only be a directory
    }
} catch (IOException ex) {
    // An I/O problem has occurred
}

@Gamby 请提供最小可复现代码。 - spongebob

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接