JDK11环境下Java写入约5GB大文本文件的最快实现方法
JDK11 5GB级别大文本文件最高效写入方案
原代码问题分析
- 缓冲区配置仅为48KB,对于GB级大文件而言过小,会导致频繁的用户态/内核态切换,大幅降低IO效率
- 额外包装的
PrintWriter引入了不必要的方法调用、异常检查开销,且PrintWriter默认吞掉IO异常,不利于问题排查
优化方案
1 基础优化方案(适配绝大多数场景,改动最小)
直接使用JDK11 NIO.2提供的Files.newBufferedWriter,将缓冲区调整到1MB~8MB区间(该区间的IO性能提升最明显,更大的缓冲区边际收益极低),同时避免逐行写入时不必要的flush操作:
import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Paths; import java.nio.file.StandardOpenOption; import java.io.BufferedWriter; // 示例代码 try (BufferedWriter writer = Files.newBufferedWriter( Paths.get(originalPath), StandardCharsets.UTF_8, // 显式指定编码避免平台兼容问题 StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING)) { // 写入逻辑:不需要每写一行就flush,流关闭时会自动刷盘 for (String line : yourContentLines) { writer.write(line); writer.newLine(); // 禁止此处加writer.flush(),会强制触发磁盘写入拉低效率 } } catch (IOException e) { // 自定义处理IO异常 e.printStackTrace(); }
该方案相比原代码,写入效率可提升3~10倍。
2 极致性能优化方案(适合对写入速度要求极高的场景)
直接使用FileChannel配合堆外直接缓冲区,跳过字符流编解码的额外开销,同时减少JVM堆内存的GC压力:
import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.nio.charset.StandardCharsets; import java.nio.file.Paths; import java.nio.file.StandardOpenOption; // 示例代码 try (FileChannel channel = FileChannel.open( Paths.get(originalPath), StandardOpenOption.CREATE, StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING)) { // 分配4MB堆外直接缓冲区 ByteBuffer buffer = ByteBuffer.allocateDirect(4 * 1024 * 1024); String lineSeparator = System.lineSeparator(); for (String line : yourContentLines) { byte[] lineBytes = (line + lineSeparator).getBytes(StandardCharsets.UTF_8); // 缓冲区不足时先刷入磁盘 if (buffer.remaining() < lineBytes.length) { buffer.flip(); channel.write(buffer); buffer.clear(); } buffer.put(lineBytes); } // 写入缓冲区剩余的内容 buffer.flip(); channel.write(buffer); } catch (IOException e) { e.printStackTrace(); }
该方案相比基础优化方案,写入效率可再提升20%~50%。
内容的提问来源于stack exchange,提问作者Tanvi Mangesh Kasture
相关产品推荐
相关产品推荐

