bufferedreader缓冲区大小重要但非越大越好,默认8kb适合多数场景;读取日志等小文件保持默认,批量处理大文本可设64kb并配合mark/reset;需显式指定字符集、避免流重复关闭、优先用try-with-resources管理生命周期。

BufferedReader 的缓冲区大小真的重要吗
重要,但不是越大越好。默认 8192 字节(8KB)已覆盖多数场景,盲目调大反而可能浪费堆内存或拖慢小文件读取——JVM 需要分配连续数组,且大缓冲区会延迟数据到达应用层的时间。
实操建议:
- 读取日志、配置等行数少但频繁打开的文件,保持默认即可
- 批量处理大文本(如 CSV 导入),可设为
64 * 1024(64KB),但需配合reset()和mark(65536)使用(注意:mark()参数不能超过缓冲区大小) - 避免设为
Integer.MAX_VALUE或兆级数值——new BufferedReader(reader, 1024 * 1024 * 100)极易触发 OOM
readLine() 为什么有时返回 null 却没到文件末尾
本质是流提前关闭或底层 Reader 被复用。常见于包装了 InputStreamReader 但未指定字符集,导致乱码截断;或在 try-with-resources 中错误地关闭了外层流却重复调用 readLine()。
典型错误现象:readLine() 突然返回 null,但文件明显还有内容;或抛出 IOException: Stream closed。
立即学习“Java免费学习笔记(深入)”;
实操建议:
- 始终显式传入字符集:
new InputStreamReader(in, StandardCharsets.UTF_8) - 确认
BufferedReader是最外层资源,不要在它之外再封装其他Closeable - 避免在循环中反复创建
BufferedReader实例——每次新建都重置缓冲区,失去缓存意义
和 Scanner 比,BufferedReader 在什么场景下更稳
纯文本按行解析、对性能敏感、需精确控制缓冲行为时,BufferedReader 更可靠。而 Scanner 内部虽也用缓冲,但额外做了 token 分割、类型转换、正则匹配,开销不可忽略,且异常行为更隐蔽(比如 nextInt() 不消费换行符,导致后续 nextLine() 返回空字符串)。
实操建议:
- 读取日志行、HTTP 响应体、CSV 行数据,优先用
BufferedReader.readLine() - 需要跳过空白、拆分字段、转数字时,先用
BufferedReader读整行,再用String.split()或StringTokenizer处理——比Scanner更可控 - 若必须用
Scanner,记得调用useDelimiter("\n")并检查hasNextLine(),而非依赖hasNext()
close() 忘记调用会导致什么后果
不只是“可能泄露文件句柄”——在 Windows 上常表现为文件被占用无法删除;在 Linux 上可能耗尽 ulimit -n 设置的文件描述符上限,导致新 socket 连接失败或 IOException: Too many open files。
更隐蔽的问题是:BufferedReader 缓冲区中未读完的数据会直接丢弃,且不会报错。
实操建议:
- 务必用 try-with-resources:
try (BufferedReader br = new BufferedReader(...)) { ... } - 若无法用 try-with-resources(如需跨方法传递),确保在 finally 块中调用
br.close(),并捕获IOException(虽然通常可忽略,但不写 catch 会编译失败) - 不要依赖
finalize()或 JVM 退出时自动清理——生产环境里,流泄漏往往在压测几天后才暴露
缓冲区大小、字符集、资源生命周期这三个点,最容易在代码 review 时被跳过,但恰恰是线上 IO 故障最常见的根因。










