

新闻资讯
技术学院本文详解如何优化 go 中大规模 csv 文件的按列分流处理,避免内存爆炸与频繁文件重写,通过流式读取 + 并发写入 + csv.writer 复用显著提升性能。
Go 在处理大 CSV 文件时若采用 csv.NewReader.ReadAll() 全量加载到内存,再逐行拼接字符串并反复调用 os.Create() 和 WriteString() 写入文件,会导致严重性能瓶颈——这正是原代码运行缓慢的根本原因。其问题集中在三点:
一文件被打开、覆盖、关闭数千次; ✅ 正确解法是流式处理 + 分离关注点:
以下是优化后的完整可运行代码:
package main
import (
"encoding/csv"
"fmt"
"os"
"sync"
)
func main() {
input, err := os.Open("union_exp.csv")
if err != nil {
fmt.Printf("Error opening input file: %v\n", err)
return
}
defer input.Close()
reader := csv.NewReader(input)
reader.FieldsPerRecord = -1 // 允许变长字段(兼容不同行)
// 读取 header 行
headers, err := reader.Read()
if err != nil {
fmt.Printf("Error reading header: %v\n", err)
return
}
// 管理各输出文件的 channel 和 goroutine
files := make(map[string]chan []string)
var wg sync.WaitGroup
// 逐行处理数据行
for {
record, err := reader.Read()
if err == csv.ErrFieldCount {
fmt.Printf("Warning: skipping malformed line (field count mismatch)\n")
continue
}
if err == io.EOF {
break
}
if err != nil {
fmt.Printf("Error reading record: %v\n", err)
return
}
if len(record) == 0 {
continue // 跳过空行
}
country := record[0]
ch, exists := files[country]
if !exists {
ch = make(chan []string, 1024) // 缓冲 channel 减少 goroutine 阻塞
files[country] = ch
wg.Add(1)
go fileWriter(country+".csv", ch, &wg, headers)
}
ch <- record // 发送数据行(header 已在 goroutine 中写入)
}
// 关闭所有 channel,通知 writer 结束
for _, ch := range files {
close(ch)
}
wg.Wait()
fmt.Println("All files written successfully.")
}
func fileWriter(filename string, ch chan []string, wg *sync.WaitGroup, headers []string) {
defer wg.Done()
f, err := os.Create(filename)
if err != nil {
fmt.Printf("Error creating %s: %v\n", filename, err)
return
}
defer f.Close()
writer := csv.NewWriter(f)
defer writer.Flush() // 必须调用 Flush 才能写出缓冲内容
// 写入 header
if err := writer.Write(headers); err != nil {
fmt.Printf("Error writing header to %s: %v\n", filename, err)
return
}
// 写入所有数据行
for record := range ch {
if err := writer.Write(record); err != nil {
fmt.Printf("Error writing record to %s: %v\n", filename, err)
return
}
}
}⚠️ 关键注意事项:
通过以上重构,处理 GB 级 CSV 文件的耗时可从分钟级降至秒级,真正发挥 Go 在高吞吐 I/O 场景下的优势。