更快地获取大型目录内容(java.io.File 个备选方案)
Get large directory content faster (java.io.File alternatives)
我已经使用旧的、过时的 java.io.File.listFiles()
太久了。
表现不太好。它是:
- 昂贵,因为它会为每个条目创建一个新的
File
对象。
- 慢,因为你必须等待数组完成才能开始处理。
- 非常糟糕,尤其是当您只需要处理内容的子集时。
有哪些选择?
Java 7 的 java.nio.file
包可用于增强性能。
迭代器
DirectoryStream<T>
接口可用于循环访问目录,而无需将其内容预加载到内存中。
旧的 API 创建文件夹中所有文件名的数组,而新方法在迭代过程中遇到每个文件名(或有限大小的缓存文件名组)时加载它。
要获取表示给定 Path
, the 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
, starting with Java 8 you could implement it with a lambda expression, overriding the Filter<T>.accept(T)
method which decides if the given directory entry should be accepted or filtered. Then you would use the 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
}
我已经使用旧的、过时的 java.io.File.listFiles()
太久了。
表现不太好。它是:
- 昂贵,因为它会为每个条目创建一个新的
File
对象。 - 慢,因为你必须等待数组完成才能开始处理。
- 非常糟糕,尤其是当您只需要处理内容的子集时。
有哪些选择?
Java 7 的 java.nio.file
包可用于增强性能。
迭代器
DirectoryStream<T>
接口可用于循环访问目录,而无需将其内容预加载到内存中。
旧的 API 创建文件夹中所有文件名的数组,而新方法在迭代过程中遇到每个文件名(或有限大小的缓存文件名组)时加载它。
要获取表示给定 Path
, the 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
, starting with Java 8 you could implement it with a lambda expression, overriding the Filter<T>.accept(T)
method which decides if the given directory entry should be accepted or filtered. Then you would use the 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
}