Files.newBufferedWriter()默认使用8192字符缓冲区,无法直接设置大小;需通过OutputStreamWriter+Files.newOutputStream手动组合并传入自定义缓冲区大小。
java 的 files.newbufferedwriter() 默认使用 8192 字节(8kb)缓冲区,这个值对多数场景够用,但写入超大文本文件(如 gb 级日志、导出数据)时,适当增大缓冲区可显著减少系统 i/o 调用次数,降低上下文切换开销,提升吞吐量。关键在于:它本身不直接提供“设置缓冲区大小”的重载方法,必须通过包装 outputstreamwriter 实现。
用 OutputStreamWriter + FileOutputStream 显式控制缓冲区
这是最直接、最可控的方式。绕过 Files.newBufferedWriter() 的默认封装,手动组合底层组件:
- 先用
Files.newOutputStream()获取带自动创建父目录能力的OutputStream - 将其传给
OutputStreamWriter,并指定字符集和自定义缓冲区大小(单位:字符数,非字节数) - 再将该 writer 包装进
BufferedWriter(可选,但推荐——因为OutputStreamWriter自身缓冲的是字符,而BufferedWriter缓冲的是行/块,二者作用不同)
示例代码:
Path path = Paths.get("output.txt");
int bufferSize = 64 * 1024; // 64KB 字符缓冲(约 128KB UTF-8 字节,取决于内容)
Charset charset = StandardCharsets.UTF_8;
<p>try (BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(
Files.newOutputStream(path, CREATE, WRITE),
charset),
bufferSize)) {</p><pre class="brush:php;toolbar:false;">for (int i = 0; i < 1_000_000; i++) {
writer.write("Line " + i + "\n");
}}
注意:BufferedWriter 构造器中的 bufferSize 指的是内部字符数组长度(单位:char),不是字节。UTF-8 下一个中文字符占 3 字节,所以 64KB 字符 ≈ 最多 128KB+ 的实际字节输出(取决于文本组成)。
立即学习“Java免费学习笔记(深入)”;
为什么不能直接用 Files.newBufferedWriter() 设缓冲区?
Files.newBufferedWriter() 是个便捷工厂方法,其内部固定调用 new BufferedWriter(new OutputStreamWriter(...), 8192),硬编码了 8192 字符缓冲。JDK 没有暴露缓冲区参数的重载版本。试图通过反射修改或继承绕过,既破坏封装,又不可靠,不推荐。
缓冲区大小怎么选?常见参考值
没有绝对最优值,需结合磁盘类型、JVM 堆、数据特征权衡:
- SSD + 连续写入:32KB–256KB 较稳妥;超过 512KB 收益递减,还可能增加单次 flush 延迟
- HDD 或网络存储:建议 64KB–128KB,太小导致频繁寻道,太大无明显增益
- 内存敏感场景(如容器环境):避免 >256KB,防止 writer 对象长期占用大块堆内存
-
含大量短行(如 CSV):适当增大(如 128KB),减少
write(String)和newLine()的缓冲区填满频率
实测中,从默认 8KB 提升到 64KB,GB 级纯文本顺序写入常可提速 15%–35%,具体看硬件和 JVM GC 压力。
别忽略 flush 和 close 的时机
增大缓冲区后,flush() 触发的 I/O 更“重”,要避免高频手动 flush。合理策略是:
- 仅在必须保证数据落盘时(如关键日志、事务边界)才显式
flush() - 依赖 try-with-resources 自动
close(),它会隐式 flush + 关闭底层流 - 若写入中途崩溃,未 flush 的缓冲数据会丢失——这是缓冲带来的权衡,业务需评估是否可接受
不复杂但容易忽略。



















