FileReader 文件字符读取
你有没有遇到过这种情况:本地测试好好的,代码一部署到服务器,中文全变成乱码了?
大概率是 FileReader 惹的祸。
FileReader 是 Java 读取文本文件最简单的方式——直接按字符读取,不用手动处理字节到字符的转换。但它的「简单」背后,藏着一个跨平台陷阱。
基本用法
java
// 方式 1:字符串路径
FileReader fr = new FileReader("data.txt");
// 方式 2:File 对象
FileReader fr = new FileReader(new File("data.txt"));
// ❌ 陷阱:没有 (File, Charset) 构造函数!
// FileReader 永远用平台默认编码,跨平台就是坑核心问题:FileReader 无法指定字符编码。它内部直接调用平台默认编码——Windows 是 GBK,macOS 和 Linux 是 UTF-8。
两种读取方式
单字符读取(慢,不推荐)
java
try (FileReader fr = new FileReader("data.txt")) {
int c;
while ((c = fr.read()) != -1) {
System.out.print((char) c);
}
}
// 每次 read() 返回一个字符,每读一个字符触发一次系统调用
// 大文件读取极慢批量读取(推荐)
java
try (FileReader fr = new FileReader("data.txt")) {
char[] buffer = new char[1024];
int len;
while ((len = fr.read(buffer)) != -1) {
String s = new String(buffer, 0, len);
System.out.print(s);
}
}
// 批量读取大幅减少系统调用次数为什么你的中文乱码了
看一个具体的乱码场景:
文件保存为 UTF-8:"你好 Java"
UTF-8 字节:[228, 184, 173, 229, 155, 189, 32, 74, 97, 118, 97]
────────────────────────────── "你好"(各3字节)
───────── "Java"(ASCII)
用 GBK 读取:
[228, 184, 173, 229, 155, 189, 32, ...]
→ 按 GBK 解码:228(露) 184(?) 173(?) 229(?) 155(?) 189(?)
→ 乱码!
用 UTF-8 读取:
[228, 184, 173, 229, 155, 189, 32, ...]
→ 按 UTF-8 解码:228,184,173 → 你;229,155,189 → 好
→ 正常!本地测试正常,服务器乱码?大概率是编码不一致。
正确做法:InputStreamReader + 指定编码
java
// ❌ 错误:依赖平台默认编码
FileReader fr = new FileReader("utf8.txt");
// Windows 用 GBK 读 UTF-8 文件 = 乱码
// ✅ 正确:用 InputStreamReader 指定编码
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(
new FileInputStream("utf8.txt"), StandardCharsets.UTF_8))) {
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
}原则:永远不要直接用 FileReader 读取非 ASCII 文本。
配合 BufferedReader 使用
java
// FileReader + BufferedReader:加缓冲 + readLine()
try (
BufferedReader reader = new BufferedReader(
new FileReader("data.txt"))
) {
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
}readLine() 返回 null 表示流结束,返回的字符串不包含换行符。
常用方法速查
| 方法 | 说明 |
|---|---|
read() | 读 1 字符,返回 int(0~65535),-1 表示结束 |
read(char[] cbuf) | 读到字符数组,返回实际读取的字符数 |
skip(long n) | 跳过 n 字符 |
close() | 关闭流 |
选型建议
| 场景 | 推荐方式 |
|---|---|
| 快速测试/演示 | FileReader(仅限纯英文或明确知道编码的场景) |
| 生产环境 | BufferedReader + InputStreamReader + 指定编码 |
| 大文件 | 流式读取,不要全量加载到内存 |
java
// 生产环境推荐写法
try (
BufferedReader reader = new BufferedReader(
new InputStreamReader(
new FileInputStream("data.txt"), StandardCharsets.UTF_8))
) {
reader.lines()
.forEach(System.out::println);
}记住这个教训:
FileReader三个字,换来乱码一整天。 生产环境永远用InputStreamReader+ 显式编码。
