应采用流式逐行处理避免内存溢出,优先用指定字符集和64kb缓冲区的bufferedreader,超大行或特殊格式时改用scanner或nio channel+bytebuffer按块解析。

直接用 Files.readAllLines() 或 FileUtils.readLines() 读取大文本文件,会把全部内容加载进内存,几 GB 的文件瞬间触发 OutOfMemoryError。关键不是“怎么读得更快”,而是“怎么不把整份文件塞进堆里”。
别一次性全读进内存
Guava 的 Files.readAllLines()、Commons IO 的 FileUtils.readLines() 都会返回 List<string></string>,意味着每行字符串对象 + 整个列表结构全驻留在堆中。600MB CSV 文件可能撑爆 2GB 堆空间。
- 绝对避免:
readAllLines()、readFileToString()、IOUtils.toString(inputStream) - 改用流式逐行处理:只保留当前行,处理完即丢弃,内存占用基本恒定
用 BufferedReader 按行流式读取
这是最常用也最稳妥的方式,配合合理缓冲区大小(如 64KB),系统调用少、内存低、兼容性好。
- 示例代码中显式指定字符集(如 UTF-8),避免平台默认编码导致乱码
- 缓冲区设为
64 * 1024(64KB),比默认 8KB 更少 IO 次数,又不显著增加内存压力 - 确保
try-with-resources正确关闭流,防止句柄泄漏
超大文件或需更高控制力时用 Scanner
对格式松散、含空行或特殊分隔符的文本更友好,内部也做缓冲,适合日志、配置类文件。
- 构造时传入
Charset,避免依赖系统默认编码 - 用
hasNextLine()+nextLine()循环,不缓存历史行 - 注意:若某一行超长(如单行几百 MB),仍可能触发 OOM,此时应切换为按块读取
二进制/非结构化大文本考虑 NIO Channel + ByteBuffer
当文件不含标准换行符、或需跳过头部/尾部、或需随机访问某段内容时,传统按行读取失效,应转向字节级控制。
- 使用
FileChannel打开文件,分配固定大小ByteBuffer(如 1MB) - 手动解析换行符(
\n或\r\n),拼接完整行后再处理 - 优势在于零拷贝潜力、内存可控、支持 position 定位,适合 CSV 解析器底层或日志切割工具
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











