使用 bufio 包通过内存缓冲区批量读写,减少系统调用次数;读取推荐 64KB 缓冲区配合按行读取,写入需调用 Flush 确保数据落盘。

在 Go 中优化文件读写性能,核心是减少系统调用次数、降低 I/O 等待开销,并合理利用 CPU 和磁盘带宽。缓冲(bufio)解决小粒度读写的 syscall 开销,并发处理则适用于多文件或大文件分块场景——但要注意:单个文件的顺序读写加 goroutine 并不会提速,反而可能因调度和锁竞争变慢。
用 bufio 包替代原生 os.File 读写
直接调用 file.Read() 或 file.Write() 每次都触发系统调用,频繁读取小数据(如逐行、逐字节)时性能极差。bufio 通过内存缓冲区批量操作,显著减少 syscall 次数。
- 读文件:用
bufio.NewReaderSize(file, 64*1024)设置 64KB 缓冲区(常见磁盘页大小),再配合ReadString('\n')或ReadBytes('\n')高效按行处理 - 写文件:用
bufio.NewWriterSize(file, 1(64KB),写完务必调用w.Flush(),否则内容可能滞留在缓冲区 - 避免对同一文件句柄混用
os.File原生方法和bufio,易导致读写位置错乱
对多文件任务启用并发处理
当需批量处理大量独立文件(如日志归档、图片缩放、CSV 解析),可为每个文件启动 goroutine,配合 sync.WaitGroup 控制生命周期。
- 限制并发数:用带缓冲的 channel(如
sem := make(chan struct{}, 10))控制最大 10 个 goroutine 同时运行,防内存暴涨或磁盘 IO 打满 - 错误收集:每个 goroutine 将错误 send 到统一 error channel,主 goroutine 汇总处理
- 示例场景:遍历目录下 1000 个 JSON 文件并解析 → 并发解析比串行快数倍(取决于磁盘类型和 CPU 核心数)
大文件分块读写 + sync.Pool 复用缓冲
处理 GB 级单文件时,一次性加载到内存不可行。应分块读取(如每次 1MB),并复用字节切片避免高频 GC。
立即学习“go语言免费学习笔记(深入)”;
- 用
file.ReadAt(buf, offset)随机读取指定偏移,适合并行分块(注意:需确保文件不被其他进程修改) - 定义全局
var bufPool = sync.Pool{New: func() interface{} { return make([]byte, 0, 1,每次从池中取缓冲,用完bufPool.Put(buf) - 写入时同样分块,用
file.WriteAt(buf, offset)并发写(仅限支持随机写的文件,且需保证 offset 不重叠)
绕过用户态缓冲:使用 O_DIRECT(Linux)或 FILE_FLAG_NO_BUFFERING(Windows)
极端场景(如数据库、高性能存储服务)需要绕过内核 page cache,直接与磁盘交互,避免 double buffering。但这要求:
- 缓冲区地址和长度必须对齐(通常 512B 或 4KB),可用
syscall.Mmap或alignedalloc分配 - 文件需以
syscall.O_DIRECT(Linux)打开,且每次读写偏移和长度必须对齐 - 普通应用极少需要,误用会导致 panic 或性能更差,建议仅在压测验证后采用











