files.walk() 遍历易因符号链接或权限问题中断,需用 simplefilevisitor 捕获异常并返回 continue;编码应自动探测或优先试 utf-8/gbk;正则须缓存 pattern 实例,避免贪婪匹配;定位行号宜用 bufferedreader 逐行读取。

用 Files.walk() 遍历文件但卡死或漏文件?
Java 里想搜某个目录下所有含关键词的文本文件,第一反应常是 Files.walk() ——但它默认不处理符号链接、不跳过权限不足的目录,遇到循环软链或 Permission denied 直接抛 IOException 中断整个遍历。
- 加
FileVisitOption.FOLLOW_LINKS前先确认是否真需要跟进软链,否则可能陷入无限递归 - 必须用
SimpleFileVisitor自定义访问逻辑,捕获IOException并在visitFileFailed()里返回FileVisitResult.CONTINUE,否则遍历提前终止 - 大目录下
Files.walk()会一次性加载全部路径到内存,改用Files.walk(path, 10) // 深度限制或流式处理更稳
读取文件内容时 UTF-8 解码乱码?
很多日志或配置文件实际是 GBK、ISO-8859-1 编码,硬写 StandardCharsets.UTF_8 会导致中文全变成 ??? 或抛 MalformedInputException。
- 别猜编码,用
InputStream+UniversalDetector(juniversalchardet)自动探测,小文件可接受 10–20ms 开销 - 实在要手动指定,优先试
StandardCharsets.UTF_8和Charset.forName("GBK"),Windows 上.txt文件大概率是后者 - 用
Files.readString(path, charset)替代new String(Files.readAllBytes(path), charset),前者内部做了 BOM 处理,对带 BOM 的 UTF-8 更友好
正则匹配 Pattern.compile() 慢得离谱?
每次搜索都调 Pattern.compile("keyword"),看似没问题,但编译正则本身有开销;更糟的是用 .*keyword.* 这类贪婪表达式匹配长行,会触发回溯爆炸,10KB 行直接卡住。
- 把
Pattern实例缓存为static final,尤其当关键词固定或变化不多时 - 纯文本搜索别用正则,改用
String.contains()或CharSequence.indexOf(),快一个数量级 - 非得用正则时,避免
.*开头,换成Pattern.compile("keyword", Pattern.LITERAL)关闭元字符解析,安全又快
搜到结果却不知道在哪一行?
String.indexOf() 只返偏移量,没行号;逐行读又怕大文件 OOM。关键不是“怎么读”,而是“怎么定位”。
立即学习“Java免费学习笔记(深入)”;
- 用
BufferedReader的readLine(),配合行计数器,比全读进内存再split("\n")节省内存且天然带行号 - 如果需高亮或上下文,保留当前行和前 2 行(环形缓冲区),不用存全文
- 注意:Windows 换行是
\r\n,Linux 是\n,readLine()自动处理,别自己按\n切割
最麻烦的其实是混合编码 + 二进制文件误读 + 超大单行日志——这些不会报错,但会静默跳过或解码失败,得靠文件头魔数(如 %PDF、PK)和字节统计来预判是否跳过。










