绝大多数情况下应使用file.listfiles(),但必须先判dir.isdirectory()&&dir.canread(),再判children!=null,否则符号链接、权限不足等场景会返回null导致nullpointerexception。

用 File.list() 还是 File.listFiles()?别掉进空指针陷阱
直接说结论:绝大多数情况下,该用 File.listFiles(),但必须先判空、再判是否为目录——否则一碰符号链接、权限不足或已删除路径,listFiles() 就返回 null,后续调用直接 NullPointerException。
常见错误现象是程序在某些子目录突然崩溃,报错堆栈里只看到 java.lang.NullPointerException,没线索。其实八成是这里没防护。
-
File.list()返回String[],对不存在/无权限目录返回null;listFiles()返回File[],同样返回null,不是空数组 - 必须写成:
if (dir.isDirectory() && dir.canRead()) { File[] children = dir.listFiles(); if (children != null) { ... } } - Windows 下遇到重定向符号链接(如 Junction)可能返回
null,Linux 下遇到挂载点权限变化也一样
递归遍历时怎么避免死循环?软链接和循环挂载是真坑
Java 的 File API 本身不区分硬链、软链、挂载点,递归时如果遇到自己指向自己的软链接(比如 /home/user/project -> /home/user/project),或者跨设备挂载的循环路径(如 /mnt/backup → /home 又被挂回),就会无限深入,直到栈溢出或文件句柄耗尽。
最稳妥的做法不是“检测链接”,而是记录已访问路径的规范路径(getCanonicalPath()),用 Set<string></string> 缓存防重。
- 每次进入目录前,先调用
dir.getCanonicalPath(),检查是否已在 visited 集合中 - 不要用
getAbsolutePath(),它不解析符号链接,无法识别循环 - 注意
getCanonicalPath()可能抛IOException(如路径不存在),需捕获处理 - 性能影响很小,一次哈希查表,比反复 stat 开销低得多
字符串匹配用 String.contains() 还是 Pattern?看场景别硬套正则
搜索文件名或内容时,90% 的需求只是“包含某几个字”或“以某前缀开头”,这时候用 Pattern 不仅慢,还容易因未转义 .、* 等字符导致误匹配甚至拒绝服务(ReDoS)。
只有明确需要模糊匹配(如 “log_202[3-5]_*.txt”)或跨行搜索内容时,才值得上正则。
- 文件名匹配优先用
fileName.startsWith("log_")、fileName.contains("error") - 内容搜索若只需简单子串,用
line.indexOf(keyword) >= 0比matches()快 3–5 倍 - 真要用正则,务必预编译:
private static final Pattern PATTERN = Pattern.compile(Pattern.quote(keyword)),避免每次新建 - 读取大文件时,别把整文件 load 到内存再 match,用
BufferedReader逐行 scan
为什么搜索结果顺序总“不对”?File.listFiles() 不保证顺序
很多人发现搜索结果一会儿按字母排、一会儿乱序,以为是 bug。其实 File.listFiles() 的返回顺序完全取决于底层文件系统(ext4、NTFS、APFS)和 JVM 实现,JDK 文档白纸黑字写着:“no guarantee is made as to the order”。想稳定排序,必须自己做。
尤其当你要做“找最近修改的前 10 个日志”或“按名称分页显示”时,顺序不可控会直接导致逻辑错乱。
- 排序前务必确认数组非
null,否则Arrays.sort()直接 NPE - 按名称排序:
Arrays.sort(files, Comparator.comparing(File::getName)) - 按修改时间倒序:
Arrays.sort(files, (a, b) -> Long.compare(b.lastModified(), a.lastModified())) - 注意
lastModified()精度在 FAT32 上只有 2 秒,在某些 NAS 上可能更粗,别拿它做精确去重
递归 + 排序 + 安全防护这三块,漏掉任何一块,看似能跑通的小工具,上线后早晚在某个边缘路径上卡死或错漏。特别是路径规范和空值判断,写一次少 debug 三天。










