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

Fra*_*ani 14 java file-io java-7 directory-content

我已经使用旧的,过时java.io.File.listFiles()的了.

表现不太好.它是:

  • 昂贵,因为它File为每个条目创建一个新对象.
  • 慢,因为在开始处理之前必须等待阵列完成.
  • 非常糟糕,特别是如果您只需要处理内容的子集.

有哪些替代方案?

Fra*_*ani 26

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
}
Run Code Online (Sandbox Code Playgroud)

过滤器

该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
}
Run Code Online (Sandbox Code Playgroud)
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
}
Run Code Online (Sandbox Code Playgroud)