bufferedreader 必须包装 reader 实例(如 inputstreamreader)才能使用,虽可配合 filereader,但因后者强制使用默认编码易致乱码;推荐 fileinputstream + inputstreamreader(显式指定 utf-8)+ bufferedreader 组合以确保编码可控和按行高效读取。

FileReader 不能直接和 BufferedReader 配合使用?
不是不能,而是 FileReader 本身已经是一个字符流读取器,它底层封装了 InputStreamReader(用默认平台编码),但它的设计定位是「简单读字符」,不支持缓冲、mark/reset、高效按行读取等能力。真正该配合 BufferedReader 的,是 InputStreamReader——而 FileReader 只是它的简化封装版,**丢掉了编码控制权和灵活性**。
所以常见错误是这样写:
new BufferedReader(new FileReader("a.txt"))
表面能跑,但隐患明显:
-
FileReader强制使用系统默认编码(比如 Windows 上是 GBK),遇到 UTF-8 文件且含中文时大概率乱码 - 无法显式指定 BOM 处理逻辑(如跳过
\uFEFF) - 一旦文件编码非默认,问题暴露得晚(读出来字串长度不对、
split("\n")失效、正则匹配失败)
正确组合:用 FileInputStream + InputStreamReader + BufferedReader
这才是可控、可复现、可调试的文本按行读取链路。关键在于把编码决策权拿回来,同时保留 BufferedReader 的 readLine() 效率和换行符屏蔽能力。
实操建议:
- 用
FileInputStream打开文件(二进制安全,不碰编码) - 套一层
InputStreamReader,明确传入编码(如"UTF-8"),并可选启用 BOM 检测(需手动处理) - 再包一层
BufferedReader,调用readLine()—— 它会自动吞掉\r\n、\n、\r,返回纯净行内容
示例(Java 8+):
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(
new FileInputStream("data.txt"),
StandardCharsets.UTF_8))) {
String line;
while ((line = reader.readLine()) != null) {
// line 已去除换行符,内容完整
System.out.println(line);
}
}
readLine() 返回 null 的唯一含义就是流已结束
别把它当成“空行”或“解析失败”的信号。空行会被正常返回为 "" 字符串;只有到文件末尾、且没有更多字符可读时,readLine() 才返回 null。
容易踩的坑:
- 误判
if (line == null)是异常,其实只是循环该停了 - 用
while (reader.ready())包裹readLine()—— 这会导致最后一行被跳过(ready()在 EOF 前可能返回 false) - 对每行做
line.trim().isEmpty()判断是否为空行,而不是用line == null
大文件或需跳过 BOM 时必须手动检测
InputStreamReader 不会自动跳过 UTF-8 BOM(\uFEFF),如果文件带 BOM,第一行开头会出现不可见字符,导致 line.startsWith("#") 失败、JSON 解析报错等。
解决方式(在构造 BufferedReader 前处理):
- 用
FileInputStream读前 3 字节,判断是否为0xEF 0xBB 0xBF - 如果是,调用
skip(3),再把流交给InputStreamReader - 或者更稳妥:用 Apache Commons IO 的
org.apache.commons.io.input.BOMInputStream,它提供getBOM()和自动跳过能力
纯 JDK 方案示例片段:
FileInputStream fis = new FileInputStream("config.txt");
// 检查并跳过 UTF-8 BOM
if (hasUtf8Bom(fis)) {
fis.skip(3);
}
BufferedReader reader = new BufferedReader(
new InputStreamReader(fis, StandardCharsets.UTF_8));
BOM 检测逻辑虽小,但漏掉就会让整条解析链路输出异常结果——尤其在配置文件、CSV、日志回放等场景下,第一行数据错位往往最难排查。











