必须显式指定字符编码、设置64KB缓冲区、用try-with-resources自动关闭、逐行处理不缓存全文;否则易乱码、I/O慢、句柄泄漏或内存溢出。

要用 BufferedReader 稳定、高效地读取大文本文件(比如几 GB 的日志或 CSV),关键不是“怎么写循环”,而是四个实操细节必须到位:编码指定、缓冲区调优、资源自动释放、内存不累积。
必须显式指定字符编码,避免中文乱码
系统默认编码不可靠,Windows 用 GBK,Linux/macOS 多用 UTF-8,直接 new FileReader("file.txt") 极易出乱码。尤其含中文、emoji 或跨平台生成的文件,务必绕过 FileReader,改用带编码的构造方式:
- Java 11+ 推荐写法:
Files.newBufferedReader(Paths.get("data.log"), StandardCharsets.UTF_8) - 低版本 Java:
new BufferedReader(new InputStreamReader(new FileInputStream("data.log"), StandardCharsets.UTF_8)) - 别用
new FileReader("...")—— 它不接受编码参数,底层依赖 system property,隐患大
把缓冲区设为 64KB,兼顾性能与内存开销
BufferedReader 默认缓冲区仅 8KB,在大文件场景下会频繁触发系统 I/O 调用,拖慢速度。设为 64KB(65536 字节)是实测较优平衡点:
- 构造时传入:
new BufferedReader(reader, 64 * 1024) - 太小(如 1KB)→ 每次 readLine() 都可能拉一次磁盘,吞吐骤降
- 太大(如 1MB)→ 堆内存浪费,GC 压力上升,但读速几乎不增
用 try-with-resources 自动关闭,杜绝句柄泄漏
BufferedReader 包装了底层 FileInputStream 和 InputStreamReader,任一未关都可能导致文件句柄耗尽(尤其在 Linux 服务端长期运行时)。try-with-resources 是唯一推荐方式:
立即学习“Java免费学习笔记(深入)”;
- 写法示例:
try (BufferedReader br = new BufferedReader(...)) { ... } - 无需手动写 finally 和 close(),即使循环中抛异常,br 也会被自动关闭
- 不要在循环里重复 new BufferedReader,否则跳行或 IOException
逐行处理、即用即弃,不缓存全文到内存
高效的核心是“流式”——每行读完立刻处理、丢弃引用,而不是 collect 到 List 或 StringBuilder:
- 正确模式:
while ((line = br.readLine()) != null) { process(line); } - 禁止使用
Files.readAllLines()或FileUtils.readLines(),百万行就可能 OOM - 空行返回
""(空字符串),不是null;只有文件结束才返回null - 处理逻辑(如解析字段、写数据库、统计计数)全放在循环体内,不 add 进集合
不复杂但容易忽略:编码、缓冲大小、自动关流、不缓存全文——这四点齐备,BufferedReader 就能稳稳扛住 10GB 文本文件。


















