BufferedReader 默认缓冲区为8192字节,是权衡系统调用开销与内存占用的经验值;readLine()对\r\n、\n、\r的处理存在跨缓冲区边界错位风险;不推荐直接包装FileInputStream,应使用Files.newBufferedReader确保编码与资源安全;相比Scanner,BufferedReader更轻量高效,适用于纯行读取。

BufferedReader 的默认缓冲区大小为什么是 8192 字节
Java 中 BufferedReader 默认使用 8192 字节(8KB)缓冲区,这是在权衡系统调用开销与内存占用后设定的经验值。底层依赖 InputStreamReader 将字节流解码为字符流,每次填充缓冲区都会触发一次或多次 read() 系统调用;太小会导致频繁读磁盘/网络,太大则浪费堆内存且可能延迟响应。
实操建议:
- 对大文件顺序读取(如日志解析),可显式增大缓冲区:用
new BufferedReader(reader, 65536)提升吞吐量 - 对低延迟场景(如交互式输入),保持默认或设为
4096更稳妥 - 注意:缓冲区大小必须 > 0,否则抛
IllegalArgumentException
readLine() 遇到 \r\n、\n、\r 时的行为差异
readLine() 判定行结束符的逻辑是:匹配 \n、\r 或 \r\n 中任意一种,且只消耗匹配到的换行符,不包含在返回字符串中。但跨缓冲区边界时容易出错——比如 \r 在当前缓冲区末尾,\n 在下一次填充的开头,此时 readLine() 会把 \r 当作行尾,把 \n 留给下一行开头,造成数据错位。
常见错误现象:
立即学习“Java免费学习笔记(深入)”;
- Windows 文件在 Linux 环境下读取出现空行(因残留
\r) - HTTP 响应体中遇到
\r\n\r\n分隔符被截断
解决办法是避免依赖 readLine() 处理非标准文本,改用 read(char[] cbuf, int off, int len) 手动控制读取,并自行处理换行逻辑。
BufferedReader 包装 FileInputStream 为何不推荐
直接包装 FileInputStream(即 new BufferedReader(new InputStreamReader(new FileInputStream(...))))虽能工作,但存在两个隐患:
- 未指定字符集,依赖 JVM 默认编码(如 Windows 上是
GBK),导致中文乱码;必须显式传入StandardCharsets.UTF_8 - 缺少资源自动管理,易泄漏文件句柄;应配合
try-with-resources使用
更安全的写法:
try (BufferedReader reader = Files.newBufferedReader(Paths.get("data.txt"), StandardCharsets.UTF_8)) {
String line;
while ((line = reader.readLine()) != null) {
// 处理 line
}
}
这利用了 Files.newBufferedReader(),内部已封装好编码与资源管理,比手拼流链更可靠。
BufferedReader 与 Scanner 在性能和语义上的根本区别
Scanner 是面向“词法解析”的高级工具,内置正则匹配、类型转换(如 nextInt())、分隔符自定义等能力;而 BufferedReader 是纯“按行/按字符”读取的低开销组件。两者不可互换替代。
性能影响明显:
- 读取百万行纯文本时,
BufferedReader.readLine()比Scanner.nextLine()快 2–3 倍 -
Scanner每次调用都需检查分隔符、跳过空白、缓存预读内容,额外开销大 - 若只需逐行处理,别用
Scanner;若需混合读取数字/字符串/跳过注释,则Scanner更合适
真正容易被忽略的是:即使关闭了 Scanner,它包装的底层 Reader 不一定被关闭(取决于构造方式),而 BufferedReader 关闭时会级联关闭其包装的 Reader。










