BufferedReader适合逐行读取大文本文件,内部8KB缓冲区减少系统调用;需配合InputStreamReader指定字符集防乱码,readLine()自动去除换行符但无法区分换行风格。

BufferedReader适合逐行读取大文本文件
当你要处理日志、CSV、配置文件这类按行组织的文本,且文件体积超过几MB时,BufferedReader比直接用FileReader或InputStreamReader快得多——它内部默认使用8KB缓冲区,减少了系统调用次数。
常见错误是把它和Scanner混用:后者虽支持按类型解析(如nextInt()),但底层仍基于BufferedReader,且自带正则匹配开销;纯文本逐行处理时,BufferedReader.readLine()更轻量、更可控。
- 适用场景:
access.log解析、SQL脚本逐行执行、TSV数据流式清洗 - 不适用场景:需要随机访问某一行、频繁倒退读取、或单次读取超长二进制块
- 注意:
readLine()返回null表示流结束,不是空字符串;空行会返回""
配合InputStreamReader指定字符编码防乱码
BufferedReader本身不处理编码,必须通过包装InputStreamReader显式传入Charset。Windows记事本保存的UTF-8无BOM文件、Linux下生成的GBK日志,若不指定编码,readLine()大概率返回乱码或抛MalformedInputException。
不要依赖平台默认编码(Charset.defaultCharset()),它在Docker容器或CI环境中常为UTF-8,但在旧版Windows服务器上可能是GBK。
立即学习“Java免费学习笔记(深入)”;
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(Files.newInputStream(Paths.get("data.txt")), StandardCharsets.UTF_8))) {
String line;
while ((line = reader.readLine()) != null) {
process(line);
}
}
readLine()性能优于read(char[])但需注意换行符丢失
readLine()自动剥离\n、\r\n、\r,返回纯内容字符串——这省事,但也意味着你无法区分原始换行风格。如果业务逻辑依赖换行符(比如校验文本协议格式),就得改用read(char[])或read()逐字节处理。
性能上,readLine()在缓冲区内做查找,比反复调用read()单字符快10倍以上;但若每行极短(平均
- 典型陷阱:用
readLine()读取HTTP响应头后,误以为Content-Length字段值包含末尾\r\n - 安全写法:对关键协议字段,用
LineNumberReader(BufferedReader子类)并启用setLineNumbering(true)辅助调试
关闭流时别漏掉try-with-resources嵌套
BufferedReader的close()会级联关闭底层InputStreamReader和FileInputStream,但前提是没被其他对象引用。常见疏漏是把BufferedReader声明在try外,或在finally里手动close却忽略NullPointerException风险。
最简方案永远是try-with-resources:它保证即使readLine()抛异常,close()仍被执行。注意资源声明顺序——越靠近new的越先关闭,所以Files.newInputStream必须包在最内层。
try (FileInputStream fis = Files.newInputStream(path);
InputStreamReader isr = new InputStreamReader(fis, UTF_8);
BufferedReader reader = new BufferedReader(isr)) {
// ...
} // 自动按 reader → isr → fis 顺序关闭
真正容易被忽略的是:BufferedReader的缓冲区在close()前未flush——但它只读,没有flush概念;重点是确保上游流(如FileInputStream)没被提前关闭或重复关闭。










