filereader默认使用系统编码(如windows的gbk),无法指定文件真实编码,导致中文乱码;应改用inputstreamreader包装fileinputstream并显式传入"utf-8"等编码,再套bufferedreader提升效率。

关键在编码匹配和流封装方式。FileReader本身不支持指定编码,直接用它读中文文件极易乱码;必须配合InputStreamReader显式声明编码,再交给BufferedReader提升效率和稳定性。
为什么FileReader单独读中文会乱码
FileReader是Java早期设计的类,底层默认使用系统默认编码(Windows常为GBK,macOS/Linux多为UTF-8),并不感知文件真实编码。当文件是UTF-8而系统是GBK时,一个中文字符被错误拆成多个字节解析,结果就是“”或问号。
- FileReader("a.txt") 等价于 InputStreamReader(new FileInputStream("a.txt"), Charset.defaultCharset())
- 它无法传入编码参数,JDK至今未扩展该构造方法
- 即使文件存为UTF-8,若系统 locale 是 zh_CN.GBK,仍可能出错
正确做法:用InputStreamReader桥接并指定编码
绕过FileReader的限制,改用字节流+指定编码的字符流组合。这是最通用、兼容性最好的方案。
- 优先用 UTF-8:InputStreamReader isr = new InputStreamReader(new FileInputStream(file), "UTF-8")
- 明确知道是 GBK(如旧版Windows导出文本):new InputStreamReader(in, "GBK")
- 搭配 BufferedReader 使用:BufferedReader br = new BufferedReader(isr)
- 务必使用 try-with-resources 自动关闭,避免资源泄漏
完整安全读取示例(含异常与关闭)
以下代码可稳定读取UTF-8或GBK中文文件,并逐行处理:
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();
}
- 若文件实际是GBK,把 "UTF-8" 换成 "GBK" 即可
- 不推荐用 FileReader + BufferedReader 组合——它没解决编码问题
- readLine() 返回 null 表示已到文件末尾,不是错误
小技巧:快速判断文件编码
没有BOM的文本常难识别。可借助简单观察辅助判断:
- 用VS Code或Notepad++打开,右下角通常显示当前识别编码
- 在Linux/macOS终端执行:file -i data.txt 查看charset字段
- 若内容中中文显示为“涓枃”之类,大概率是UTF-8被当GBK解码;反之显示为“涓枃”变“???”,可能是GBK被当UTF-8
- 不确定时,先试UTF-8;失败再试GBK/GB2312











