BufferedReader 默认缓冲区大小是8192字节;该值可按需显式调整,但需权衡内存与性能;readLine()因批量扫描复用内部缓冲区而远快于逐字节read();close()会递归关闭底层InputStream,但嵌套BufferedInputStream时需额外处理。

BufferedReader 默认缓冲区大小是多少?
默认是 8192 字节(即 8KB),由 BufferedReader(InputStreamReader) 构造时内部调用 super(in, 8192) 设定。这个值在多数场景下够用,但并非最优——比如读取超大日志文件或网络响应流时,频繁触发底层 read() 系统调用仍会造成性能瓶颈。
实操建议:
- 若已知单行长度普遍 > 2KB(如 JSON 行、CSV 长字段),可显式增大缓冲区:
new BufferedReader(new InputStreamReader(inputStream), 65536)
- 不要盲目设到几 MB:过大的缓冲区会增加内存占用,且对 GC 压力明显,尤其在高并发短连接场景下易引发
OutOfMemoryError - 注意:缓冲区大小只影响
readLine()和read(char[]),对ready()或mark()/reset()无加速作用
为什么 readLine() 比逐字节 read() 快得多?
根本区别不在“是否缓冲”,而在于 readLine() 复用了内部 char[] cb 缓冲区做批量扫描,避免反复创建临时字符串和频繁调用底层 InputStream.read();而裸调 read() 每次只取一个 int,Java 层几乎不做聚合。
常见错误现象:
立即学习“Java免费学习笔记(深入)”;
- 用
while ((c = reader.read()) != -1)读文本 → CPU 使用率飙升,吞吐量可能只有readLine()的 1/10 - 误以为 “加了 BufferedReader 就自动优化所有读法” → 实际上
read()仍走单字节路径,仅比FileInputStream.read()略快(因多了一层 char 数组中转)
正确姿势:
- 文本按行处理:坚持用
readLine() - 需按字符/块处理:用
read(char[] cbuf, int off, int len)批量填充数组,再手动解析
关闭 BufferedReader 会不会自动关闭底层 InputStream?
会,但仅限于你没额外包装其他流。BufferedReader.close() 会递归调用其 Reader 成员的 close(),而 InputStreamReader.close() 又会关闭持有的 InputStream。
容易踩的坑:
- 中间插入了
BufferedInputStream:例如new BufferedReader(new InputStreamReader(new BufferedInputStream(is)))
→ 关闭BufferedReader不会关掉最外层BufferedInputStream,必须确保它也被关闭(或改用Files.newBufferedReader(Paths.get(...))自动管理) - 使用 try-with-resources 时,若多个流嵌套,只需关最外层(
BufferedReader),但前提是构造链中没有跳过 close 的自定义 Reader - 某些旧版框架(如早期 Servlet 容器)会复用
InputStream,此时显式关闭反而导致后续读取失败 —— 这类场景应避免封装成BufferedReader,或确认容器生命周期
BufferedReader 在 NIO 场景下还有优势吗?
纯 NIO(如 FileChannel + ByteBuffer)本身已具备高效缓冲能力,此时再套 BufferedReader 反而引入额外对象开销和字符编码转换延迟。但现实开发中,绝大多数文本解析逻辑仍基于 String 和行语义,直接操作 ByteBuffer 写法复杂、易出错。
权衡建议:
- 小到中等文件(BufferedReader,配合合理缓冲区大小即可
- 超大文件流式处理(如日志归档分析)、追求极致吞吐:用
Files.lines(path)(返回Stream,底层仍用BufferedReader,但做了 lazy-split 和资源自动管理) - 真正需要 NIO 控制粒度(如零拷贝、部分读取、异步通知):放弃
BufferedReader,改用CharsetDecoder+ByteBuffer手动解码,但要注意换行符跨 buffer 边界的问题
最常被忽略的一点:无论用哪种方式,只要涉及字符编码(尤其是 UTF-8),BufferedReader 的缓冲区大小必须能容纳至少一个完整多字节字符 —— 否则可能在中间截断 UTF-8 序列,导致 MalformedInputException。










