FileReader默认使用系统编码(如Windows的GBK),无法指定文件真实编码,导致中文乱码;应改用InputStreamReader包装FileInputStream并显式传入"UTF-8"等编码,再套BufferedReader提升效率。
直接用 filereader + bufferedreader 读中文文件,大概率会乱码。根本原因不是代码写错了,而是 filereader 默认用系统编码(windows 是 gbk,macos/linux 通常是 utf-8),它不认你文件实际存的是什么编码。只要文件编码和系统默认编码不一致,中文就会变成“”或问号。
别用 FileReader 单独读中文文件
FileReader 的构造方法没有编码参数,new FileReader("data.txt") 等价于 new InputStreamReader(new FileInputStream("data.txt"), Charset.defaultCharset())——它绕不开系统默认编码。即使你把文件存成 UTF-8,只要系统 locale 是 zh_CN.GBK,照样出错。
- 它不能指定编码,JDK 至今没给 FileReader 加这个能力
- 它不是为跨编码场景设计的,属于早期简化 API,不适合处理中文为主的多环境部署
- BufferedReader 包一层 FileReader,只是加了缓冲和
readLine(),完全不解决编码问题
正确做法:用 InputStreamReader + FileInputStream + 编码显式声明
这是 Java 官方推荐、兼容性最好、最可控的方式。本质是“字节流 → 指定编码的字符流 → 缓冲读取”三层封装:
- 用
FileInputStream读原始字节(不碰编码) - 用
InputStreamReader显式传入真实编码,比如"UTF-8"或"GBK" - 再套
BufferedReader提升效率,支持逐行读取
示例(UTF-8 文件):
<pre>try (FileInputStream fis = new FileInputStream("data.txt");InputStreamReader isr = new InputStreamReader(fis, "UTF-8");
BufferedReader br = new BufferedReader(isr)) {
String line;
while ((line = br.readLine()) != null) {
System.out.println(line); // 中文正常显示
}
} catch (IOException e) {
e.printStackTrace();
}</pre>
怎么知道文件到底是什么编码?
没 BOM 的文本很难 100% 自动判断,但有几种实用办法:
- 用 VS Code 或 Notepad++ 打开,右下角通常直接显示识别出的编码
- Linux/macOS 终端执行:
file -i data.txt,看输出里的charset=字段 - 如果用记事本保存过,且没手动改过编码,大概率是 GBK(Windows 默认);用 VS Code 新建保存的,大概率是 UTF-8(无 BOM)
- 试读几行,用不同编码解码后观察:中文是否连贯、有无异常符号或截断
补充:浏览器端 FileReader 读本地中文文件
前端场景下,FileReader 可以指定编码:
- 现代浏览器支持
reader.readAsText(file, "UTF-8"),比不传参可靠得多 - 如果文件是 GBK(比如旧版 Excel 导出的 .txt),原生 FileReader 不支持,得先用
readAsArrayBuffer()读二进制,再用iconv-lite解码 - 快速验证是否乱码:打印
JSON.stringify(reader.result),若中文显示为"\u597d"是正常的;若出现???或空格,就是编码不匹配

















