在Golang的文件操作中,写入效率是很多场景需要关注的问题,尤其是需要频繁写入小段数据的场景,不合理的写入方式会大幅拉低程序性能。bufio包提供的Writer类型就是专门解决这类问题的工具,它通过内置缓冲区减少系统调用次数,从而提升文件写入的整体效率。

无缓冲写入的痛点
直接使用os.File的Write方法写入数据时,每一次调用都会触发一次系统调用,将数据从用户态拷贝到内核态的文件缓冲区中。如果写入的数据量很小且次数很多,大量的系统调用会消耗不少CPU资源,导致程序性能下降。
下面的代码演示了无缓冲写入的实现方式:
package main
import (
"os"
)
func main() {
// 创建或打开文件
file, err := os.OpenFile("test.txt", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
if err != nil {
panic(err)
}
defer file.Close()
// 循环写入10000次小数据
for i := 0; i < 10000; i++ {
data := []byte("hello golangn")
// 直接调用Write方法,每次都会触发系统调用
_, err := file.Write(data)
if err != nil {
panic(err)
}
}
}
使用bufio Writer实现缓冲写入
bufio.Writer会在内存中维护一个缓冲区,当我们调用它的Write方法时,数据会先写入这个缓冲区,只有当缓冲区满了,或者我们手动调用Flush方法时,才会将缓冲区的数据一次性写入到底层的文件中,这样就大幅减少了系统调用的次数。
基本使用步骤
- 先通过os包打开或创建目标文件,得到
os.File实例 - 使用bufio.NewWriter或者bufio.NewWriterSize创建Writer实例,后者可以自定义缓冲区大小
- 调用Writer的Write方法写入数据到缓冲区
- 写入完成后调用Flush方法将剩余缓冲区数据刷入文件
- 注意处理可能的错误,并且及时关闭文件
缓冲写入示例代码
下面是使用bufio.Writer实现同样写入10000次小数据的代码:
package main
import (
"bufio"
"os"
)
func main() {
// 打开文件
file, err := os.OpenFile("test_buff.txt", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
if err != nil {
panic(err)
}
defer file.Close()
// 创建缓冲写入器,默认缓冲区大小为4096字节
writer := bufio.NewWriter(file)
// 也可以自定义缓冲区大小,比如设置为8192字节
// writer := bufio.NewWriterSize(file, 8192)
// 循环写入10000次数据
for i := 0; i < 10000; i++ {
data := []byte("hello golangn")
_, err := writer.Write(data)
if err != nil {
panic(err)
}
}
// 将缓冲区剩余数据刷入文件
err = writer.Flush()
if err != nil {
panic(err)
}
}
两种写入方式的性能对比
我们可以通过简单的基准测试来对比两种方式的性能差异,基准测试代码如下:
package main
import (
"bufio"
"os"
"testing"
)
// 无缓冲写入基准测试
func BenchmarkDirectWrite(b *testing.B) {
file, _ := os.OpenFile("bench_direct.txt", os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644)
defer file.Close()
data := []byte("hello golangn")
for i := 0; i < b.N; i++ {
file.Write(data)
}
}
// 缓冲写入基准测试
func BenchmarkBufferedWrite(b *testing.B) {
file, _ := os.OpenFile("bench_buff.txt", os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644)
defer file.Close()
writer := bufio.NewWriter(file)
defer writer.Flush()
data := []byte("hello golangn")
for i := 0; i < b.N; i++ {
writer.Write(data)
}
}
运行基准测试后,通常可以看到缓冲写入的耗时远低于无缓冲写入,写入次数越多,性能差距越明显。
使用bufio Writer的注意事项
- 一定要在写入完成后调用
Flush方法,否则缓冲区中未写满的数据会丢失,因为程序退出时不会自动刷新缓冲区 - 如果自定义缓冲区大小,需要根据实际写入的数据大小合理设置,太小起不到减少系统调用的作用,太大则会占用过多内存
- Writer的Write方法返回的错误需要关注,虽然缓冲区写入内存很少出错,但底层写入文件时可能出现错误
- 如果程序需要频繁写入并且中途可能出现异常,可以定期调用Flush方法,避免异常退出时丢失过多缓冲区数据
适用场景
bufio.Writer适合所有需要频繁写入小数据的场景,比如日志写入、数据序列化写入文件、流式数据写入等。如果是一次性写入大文件,数据量远大于缓冲区大小,那么使用缓冲写入的提升并不明显,此时可以根据实际需求选择是否使用。
Golangbufio_Writer文件写入缓冲机制修改时间:2026-06-18 18:30:30