核心答案:永远别直接用FileReader/FileWriter处理含中文的文本文件,应显式使用InputStreamReader+FileInputStream和OutputStreamWriter+FileOutputStream并传入标准编码名如"UTF-8"。

核心就一条:别直接用 FileReader 和 FileWriter,它们默认用系统编码(Windows 是 GBK,Linux/macOS 通常是 UTF-8),一碰中文就容易出错。真正靠谱的做法是用带明确编码参数的转换流。
明确指定编码,不依赖系统默认
文件读写乱码,本质是“解码时认错了门牌号”。你得告诉 Java 文件真实用的是什么编码,而不是让它猜。
- 读取时,用
InputStreamReader包装FileInputStream,构造时传入编码名,比如"UTF-8"或"GBK" - 写入时,用
OutputStreamWriter包装FileOutputStream,同样必须传编码参数 - 编码名要写标准:用
"UTF-8"(带短横线),别写"utf8"或"UTF8",否则会抛UnsupportedEncodingException
优先用 Files 工具类,更简洁安全
Java 7+ 提供了 Files 类,API 更干净,也更不容易出错。
- 读取:用
Files.newBufferedReader(Paths.get("a.txt"), StandardCharsets.UTF_8) - 写入:用
Files.newBufferedWriter(Paths.get("b.txt"), StandardCharsets.UTF_8) - 它自动处理资源关闭,不带 BOM,适合服务端、配置文件、日志等通用场景
搞不清文件编码?先查再读
别靠猜。不同来源的文件编码可能五花八门,尤其老系统或用户手动保存的文本。
立即学习“Java免费学习笔记(深入)”;
- Linux/macOS 下用命令
file -i filename.txt查看 - Windows 上用 VS Code 打开,右下角状态栏会显示当前识别的编码(如 UTF-8、GBK、ISO-8859-1)
- 如果真不确定,可尝试用
UniversalDetector(来自 ICU 或 juniversalchardet 库)做探测,但结果不是 100% 可靠,仍需验证
关于 BOM 的实际建议
BOM(\uFEFF)对 UTF-8 来说不是必需的,多数现代工具都能正确识别无 BOM 的 UTF-8 文件。
- 服务端生成 JSON、CSV、配置文件时,**绝对不要加 BOM**,否则前端解析或脚本处理会失败
- 只有明确需要兼容 Windows 记事本时,才考虑在写入前手动输出
\uFEFF,且确保 OutputStreamWriter 编码确实是 UTF-8 - 注意:BOM 在 UTF-8 中占 3 字节(EF BB BF),加错位置或重复写会导致内容偏移


















