直接用os.file.write比bufio.writer慢,因为前者每次调用都可能触发高开销系统调用,后者通过缓冲区合并小写入、减少系统调用次数;合理设置缓冲区大小需权衡内存与性能,过大会延迟数据落地、过小则降低合并效果。

为什么直接用 os.File.Write 比 bufio.Writer 慢?
因为每次调用 os.File.Write 都可能触发一次系统调用(write(2)),而系统调用开销大,尤其在写小块数据时——比如循环中反复写入几字节字符串,性能会断崖式下降。 bufio.Writer 把多次小写入暂存在内存缓冲区里,等缓冲区满、显式调用 Flush() 或关闭时,才一次性发给内核。
默认缓冲区大小是 4096 字节,这个值在大多数场景下足够平衡内存占用与系统调用频次。
bufio.NewWriter 的缓冲区大小怎么设才合理?
传入的 size 参数不是越大越好:过大会增加内存占用和延迟(数据滞留在缓冲区更久);过小则起不到合并写入的效果。常见做法:
- 写日志或配置文件(单次写入量较稳定):按典型行长度 × 10~50 估算,比如平均行长 80 字节,可设
bufio.NewWriterSize(f, 4096) - 写二进制流或已知总大小(如导出 CSV 数据集):设为总大小的 1/10~1/4,但不超过 64KB,避免 malloc 压力
- 不确定写入模式或内存敏感环境(如嵌入式):用默认值,或显式传
bufio.DefaultWriterSize
注意:如果写入量始终小于缓冲区大小且从不 Flush(),程序退出前必须 Close() 或 Flush(),否则数据丢失。
忘记 Flush() 或 Close() 会导致什么?
最常见现象是「文件看起来没写完」或「最后一段内容缺失」——比如写入 10 行,只看到前 7 行。这是因为缓冲区还没被清空到磁盘。
正确收尾方式取决于使用场景:
- 写完即用(如生成临时配置):
w.Flush()后检查错误,再f.Close() - 配合
defer使用时,不能只 deferf.Close(),必须 deferw.Flush()或把w封装成带Close()方法的结构体 - 使用
io.WriteCloser接口时,w.(io.WriteCloser).Close()会自动 flush + close,但需类型断言或接口转换
一个典型错误写法:defer f.Close() 而没处理 w,此时 f 关闭了,但 w 的缓冲区还挂着,数据就丢了。
什么时候不该用 bufio.Writer?
它不是万能加速器。以下情况反而可能变慢或出错:
- 单次写入远大于缓冲区(比如一次写 1MB),此时
bufio.Writer会先拷贝进缓冲区再 dump,多一次内存 copy - 需要实时可见(如监控日志),又没配好
Flush()时机,会导致观察延迟 - 底层
io.Writer不支持Write的部分写行为(极少见),bufio.Writer可能表现异常 - 写入目标是网络连接(如
net.Conn)且对延迟敏感,缓冲可能引入不可控时延
真正影响性能的,往往不是要不要用 bufio.Writer,而是你是否清楚它的缓冲边界在哪里、数据何时落地、以及 panic 是否会被掩盖(比如 Write() 错误被缓冲区吞掉,直到 Flush() 才暴露)。











