正确做法是用try-with-resources配合bufferedreader逐行读取并立即处理,不累积数据;错误做法包括未指定编码、忽略资源关闭或全量加载文件。

核心就一条:别把整份文件塞进内存,而是按需读、即用即弃。BufferedReader 的 readLine() 本身不导致溢出,问题出在你后续怎么存、怎么用。
用 try-with-resources 自动关流
这是底线,不是可选项。手动 close 容易遗漏,资源不释放会累积句柄、缓冲残留,最终拖垮整个读取过程。
- ✔ 正确写法(推荐):
try (BufferedReader reader = new BufferedReader(new InputStreamReader(Files.newInputStream(path), StandardCharsets.UTF_8))) {
String line;
while ((line = reader.readLine()) != null) {
processLine(line); // 立即处理,不保留引用
}
} - ✘ 错误写法:
忘记 try-with-resources、用 FileReader(不指定编码)、或在 finally 里才 close 但没判空——都可能让流长期占用,尤其在循环读多个大文件时风险极高。
逐行处理,绝不累积全部内容
readLine() 每次只加载当前行(不含换行符),内存开销是 O(单行长度),不是 O(文件总大小)。溢出只发生在你“留着不用”。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- ✅ 处理完立刻丢弃:写入数据库、输出到新文件、更新统计变量、发消息队列
- ✅ 需要上下文?只保留最小必要状态,比如前一行的 ID、累计行数、上一个时间戳
- ❌ 不要
lines.add(line)收集所有行 - ❌ 不要用
StringBuilder拼接全文或缓存多行做复杂解析
防御超长行和编码乱码
一行几 MB 的日志、缺失换行符的 dump 文件,会让 readLine() 一次性分配巨量内存。乱码则可能让解析逻辑崩溃或隐式放大内存占用。
- 明确指定字符集:
StandardCharsets.UTF_8代替系统默认编码,避免因平台差异引发异常 - 对超长行加保护(可选):读取前检查行长度,或用带超时/限制的封装工具类拦截异常长行
- 缓冲区大小可微调:默认 8KB 足够;若大量超长行且 I/O 是瓶颈,可设为 64KB,但注意这只是读取加速,不影响“按行分配”的本质
避开高危替代方案
有些看似方便的方法,实际暗藏 OOM 风险:
-
Files.readAllLines()或FileUtils.readLines():直接把全部行加载进 List,文件越大越危险 -
Files.lines().forEach(...):底层仍是 BufferedReader,但一旦链式调用.sorted()或.collect(Collectors.toList()),就等于全量加载 -
Scanner:虽支持按行,但内部缓冲机制不如 BufferedReader 稳定,且不支持显式编码设置 - Apache POI 读 Excel:.xls/.xlsx 全内存解析,大表必崩;应改用 SXSSF(流式写)或 Apache POI 的 EventModel(SAX 模式)
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










