Skip to content

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 + 显式编码。

基于 VitePress 构建