Files.newDirectoryStream()过滤器可用String glob(如".log")或DirectoryStream.Filter接口实现;glob仅支持、?、[a-z]等简单语法,不支持**、{a,b}或正则;Filter需处理IOException并用try-catch避免中断遍历。

Files.newDirectoryStream() 的过滤器参数怎么写才有效
直接传 String 模式(比如 "*.log")最省事,但仅支持简单 glob 语法,不支持正则或复杂逻辑;若需条件组合(如“大于 1MB 且修改时间在 3 天内”),必须用 DirectoryStream.Filter 接口实现——注意它是个函数式接口,可用 lambda,但别漏掉 throws IOException 声明。
常见错误是把 File 对象当参数传进去:这个方法操作的是 Path,不是 File;另一个坑是 filter 中调用 Files.size() 或 Files.getLastModifiedTime() 时没处理 IOException,会导致遍历提前中断。
推荐写法:
try (DirectoryStream<path> stream = Files.newDirectoryStream(
Paths.get("/var/log"),
entry -> {
try {
return Files.isRegularFile(entry) &&
entry.toString().endsWith(".log") &&
Files.size(entry) > 1024 * 1024;
} catch (IOException e) {
return false; // 出错跳过该条目,不中断整个流
}
})) {
for (Path path : stream) {
System.out.println(path);
}
}</path>
glob 模式里哪些通配符能用、哪些不能用
Files.newDirectoryStream(Path, String) 的第二个参数是 glob 表达式,底层由 FileSystem 解析,不是 shell,也不等价于正则。
-
*匹配任意数量字符(不含路径分隔符/) -
**不支持——想递归必须换Files.walk() -
?匹配单个字符 -
[a-z]支持字符范围,[!a]表示非 a -
{a,b,c}不支持——不能写成"{*.txt,*.log}" - 大小写敏感性取决于文件系统:Linux 默认敏感,Windows 默认不敏感
所以 "*.jpg" 可以,"*.JPG" 在 Linux 下不会匹配大写后缀;要兼容大小写,要么用 filter,要么写成 "*.{jpg,JPG,jpeg,JPEG}"(但注意:这个花括号语法实际不被 newDirectoryStream 支持,会当作字面量处理——别这么写)。
为什么遍历中途抛异常、资源没关闭
DirectoryStream 是 AutoCloseable,但很多人只记得 try-with-resources 包住创建语句,却在循环体里又调用了可能抛 IOException 的操作(比如 Files.readAllLines(path)),导致异常跳出后 stream 虽然自动 close,但上层逻辑已中断,后续文件没处理。
更隐蔽的问题是:filter 内部抛出未捕获的 RuntimeException(比如 NullPointerException),也会让整个 stream 关闭,并静默丢弃剩余条目。
实操建议:
- 所有 I/O 操作(包括 filter 内的
Files.size()、Files.isRegularFile())都包在 try-catch 里,返回false跳过当前项 - 避免在 filter 中做耗时操作(如读文件内容),否则性能急剧下降
- 确认
Path是否为符号链接:默认isRegularFile()不跟随链接,要用Files.isRegularFile(path, LinkOption.NOFOLLOW_LINKS)显式控制
和 Files.walk()、Files.list() 的关键区别在哪
三者目的相似,但行为差异直接影响是否选错:
-
Files.list():只展一层,不支持过滤器,返回Stream,适合简单场景;但它不保证顺序,也不自动 close 底层资源(需手动或用 try-with-resources 包装) -
Files.newDirectoryStream():只展一层,支持高效过滤(filter 在遍历时实时判断),资源由 stream 自己管理,内存占用低,适合“查一批符合条件的文件名” -
Files.walk():递归遍历,支持深度限制和全局 predicate 过滤,但会构建完整路径树,内存开销大;若只需首层过滤,用它纯属浪费
真正容易被忽略的一点:newDirectoryStream() 返回的 DirectoryStream 是惰性求值的,但它的迭代器不支持并发修改——遍历时不能在另一线程删除或重命名目录中的文件,否则可能抛 DirectoryIteratorException 或跳过条目。











