filereader 默认使用平台默认编码,读取 utf-8 中文文本易乱码,因其不支持显式指定编码;应改用 inputstreamreader + fileinputstream 并传入 standardcharsets.utf_8,或使用 files.lines() 指定编码安全读取。

FileReader 默认使用平台默认编码(如 Windows 的 GBK),读取 UTF-8 编码的中文文本时极易出现乱码。要正确读取含中文的文本,核心是**显式指定字符编码**——而 FileReader 本身不支持设置编码,因此不能直接用它可靠处理中文,需改用 InputStreamReader 配合 FileInputStream。
为什么 FileReader 容易读出中文乱码
FileReader 是 InputStreamReader 的子类封装,但它在构造时自动采用 Charset.defaultCharset(),该值在不同系统下可能为 GBK、ISO-8859-1 或 UTF-8,不可控。例如:UTF-8 编码的“你好”在 GBK 环境下被按双字节解析,就会变成“浣犲ソ”。这不是代码写错,而是编码契约不匹配。
推荐方案:用 InputStreamReader + FileInputStream 指定编码
这是最标准、最可控的方式,能明确指定文件真实编码:
- 先用 FileInputStream 打开文件(字节流,不涉及编码)
- 再用 InputStreamReader 包装它,并传入 Charset.forName("UTF-8") 或 StandardCharsets.UTF_8
- 最后可接 BufferedReader 提升读取效率(尤其逐行读)
示例代码:
try (FileInputStream fis = new FileInputStream("data.txt");
InputStreamReader isr = new InputStreamReader(fis, StandardCharsets.UTF_8);
BufferedReader reader = new BufferedReader(isr)) {
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line); // 中文正常显示
}
} catch (IOException e) {
e.printStackTrace();
}
替代方案:用 Files.lines()(Java 7+,简洁安全)
如果只是逐行读取,Files.lines() 内部已封装好编码处理,一行代码即可:
- 自动按指定 Charset 解码,避免手动管理流
- 返回 Stream
,支持函数式处理(如 filter、map) - 务必用 try-with-resources 或 forEachOrdered 避免资源泄漏
示例:
try (Stream<string> lines = Files.lines(Paths.get("data.txt"), StandardCharsets.UTF_8)) {
lines.forEach(System.out::println);
}
</string>
注意事项与避坑点
实际使用中需注意几个关键细节:
- 确认文件真实编码:用编辑器(如 VS Code、Notepad++)查看并保存为 UTF-8 无 BOM 格式,避免编码声明与实际不符
- 不要依赖 IDE 控制台输出判断:终端/控制台自身也有编码设置,若 cmd 或 Terminal 不支持 UTF-8,即使读对了也显示为方块或问号
- 避免混合使用 FileReader 和其他编码敏感操作:比如用 FileReader 读完再转 String,等于重复解码,必然出错
- Web 或 Spring 场景优先用 Resource 工具类:如 ClassPathResource.getFile().getAbsolutePath() + InputStreamReader,确保路径和编码双重可控
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











