根本原因是Files.readAllLines()未显式指定Charset时默认使用UTF-8解码,而GBK文件字节流被UTF-8强行解析导致解码错位;必须传入StandardCharsets.GBK等对应编码参数才能正确读取。

Files.readAllLines() 读取 GBK 文件时中文全变成乱码,根本原因是什么
不是 Files.readAllLines() 本身有问题,而是它默认用 StandardCharsets.UTF_8 解码。如果文件实际是 GBK、GB2312 或 Shift-JIS 编码,字节流被强行按 UTF-8 解析,必然出现 或异常字符——这不是“读取失败”,是解码错位。
必须显式传入 Charset,不能依赖默认值
Java 7+ 的 Files.readAllLines() 重载方法明确要求传入 Charset 参数。漏掉这一步,就等于把解码权交给 UTF-8,对非 UTF-8 文件等于直接放弃正确性。
- ✅ 正确写法:
Files.readAllLines(path, StandardCharsets.GBK) - ❌ 错误写法:
Files.readAllLines(path)(隐式 UTF-8) - ⚠️ 注意:
Charset.forName("GBK")也可用,但优先用StandardCharsets.GBK——更安全,不抛UnsupportedCharsetException
遇到 “UnsupportedCharsetException: GBK” 怎么办
这个错误只会在你用 Charset.forName("GBK") 且运行在某些精简 JRE(如部分 Docker 基础镜像、Android、或裁剪过的 OpenJDK)时出现。标准 Oracle/OpenJDK 桌面版默认支持 GBK、GB2312、Shift_JIS 等常见编码。
- 检查 JRE 是否完整:运行
java -version并确认是 full JDK/JRE,不是 headless 或 slim 版本 - 避免字符串查表:不用
Charset.forName("gbk"),大小写敏感且可能找不到;用StandardCharsets.GBK零风险 - 若真受限,可 fallback 到
new String(bytes, "GBK")+Files.readAllBytes()组合,但失去行边界自动处理
读取大文件时别硬刚 readAllLines()
Files.readAllLines() 会一次性把全部内容加载进内存并拆成 List。对几百 MB 的 GBK 日志文件,容易触发 OOM,而且你可能只需要逐行处理。
- 替代方案:用
Files.newBufferedReader(path, StandardCharsets.GBK)配合try-with-resources - 优势:流式读取,内存可控,还能用
lines().forEach(...)或skip/takeWhile等 Stream 操作 - 注意:
BufferedReader的readLine()对换行符兼容性更好(自动识别 \r\n、\n、\r),而readAllLines()在某些旧系统上可能切错行
真正麻烦的从来不是选哪个 Charset 常量,而是你得先确认文件到底是什么编码——用 file -i filename(Linux/macOS)或 chcp + 记事本另存为时看右下角编码提示,比猜可靠得多。











