应使用 try-with-resources 配合 DirectoryStream 手动计数,避免 Stream 的中间对象堆积;循环中仅声明 Path 变量且不调用 toString() 等方法,配合异常捕获确保单条目失败不影响整体,内存恒定。

用 Files.list() 统计大型目录的一级子项(不递归),关键在于**不收集全部路径到内存,而是边遍历边计数**。Java 的 Stream 默认是惰性求值,但若调用 count() 或 collect(),会触发完整遍历并可能缓存中间对象——对超大目录(如百万级文件)仍可能因路径对象开销引发 GC 压力或 OOM。
用 try-with-resources + 迭代器手动计数
绕过 Stream,直接使用 DirectoryStream 底层的迭代能力,完全避免临时 Path 对象堆积:
long count = 0;
try (DirectoryStream<Path> stream = Files.list(dirPath)) {
for (Path ignored : stream) {
count++;
}
}
说明:
-
Files.list()返回的是DirectoryStream,其迭代器是底层系统调用(如 Linux 的getdents)的封装,不预加载所有条目 - 循环中只声明
Path ignored,不存储、不打印、不调用toString(),JVM 可快速回收每个 Path 实例(尤其在开启-XX:+UseStringDeduplication时更省) - 全程无 List/Array/Stream 中间容器,内存占用恒定(约几 KB)
过滤后计数(如只统计文件或目录)
若需区分类型(例如只算普通文件),仍应避免生成新 Stream,改用条件判断:
long fileCount = 0;
try (DirectoryStream<Path> stream = Files.list(dirPath)) {
for (Path p : stream) {
if (Files.isRegularFile(p)) {
fileCount++;
}
}
}
注意:
- 不要写
Files.list(dir).filter(Files::isRegularFile).count()—— 这会为每个元素创建 Path 实例并全部保留在 Stream 管道中,压力翻倍 -
Files.isRegularFile(p)是轻量系统调用(stat),比p.toFile().isFile()更可靠且略快
处理权限异常与中断安全
真实环境常遇 AccessDeniedException(如 /proc 下某些条目),需捕获并跳过,否则遍历提前终止:
long totalCount = 0;
try (DirectoryStream<Path> stream = Files.list(dirPath)) {
for (Path p : stream) {
try {
// 可选:快速跳过符号链接(避免 resolve 开销)
if (!Files.isSymbolicLink(p)) {
totalCount++;
}
} catch (IOException | SecurityException e) {
// 忽略无法访问的条目,继续下一个
continue;
}
}
}
说明:
- 异常捕获放在循环内,确保单个条目失败不影响整体统计
- 不调用
p.getFileName()或p.toString(),避免字符串分配;如需日志调试,可加if (log.isDebugEnabled()) log.debug("skipped: {}", p);,但生产环境建议关闭
对比:为什么 Files.walk() 和 collect(Collectors.toList()) 必须避免
以下写法看似简洁,实则危险:
// ❌ 千万别这么干!
long n = Files.walk(dirPath, 1)
.skip(1) // 跳过根目录本身
.count(); // 触发全量加载 + LongStream 计数,内存暴涨
原因:
-
Files.walk()在 depth=1 时仍会为每个子项构造完整路径(如/a/b/c→/a/b/c/file1),即使你只要一级,它内部仍做路径拼接 -
count()需遍历全部元素并维护计数器,但 Stream pipeline 会持有对每个 Path 的强引用直到结束,GC 无法及时回收 - 百万级目录下,容易触发频繁 Full GC,甚至
OutOfMemoryError: Java heap space
不复杂但容易忽略:核心就一条——让 JVM 没东西可留。用原生迭代器、不存引用、早 catch 异常,百亿级目录也能毫秒出结果。

















