导出csv中文乱码需加utf-8 bom([]byte{0xef, 0xbb, 0xbf});结构体导出应实现tocsvrow()方法控制格式;大数据量须流式write+定期flush;中文文件名需用rfc 5987格式(filename*=utf-8''{url.pathescape})。

Go 导出 CSV 时中文乱码怎么办
导出 CSV 后用 Excel 打开全是方块或问号,不是 Go 本身的问题,而是 Excel 默认用 ANSI(如 GBK)读取无 BOM 的 UTF-8 文件。Go csv.Writer 输出纯 UTF-8,没加 BOM,Excel 就猜错了。
- 最简单解法:在写入第一行前,手动写入 UTF-8 BOM ——
[]byte{0xEF, 0xBB, 0xBF} - 别用
os.Create直接写,改用os.OpenFile配合io.WriteString先写 BOM,再传给csv.NewWriter - 注意:BOM 只能写一次,且必须是文件开头;如果用
bufio.Writer做缓冲,得确保 BOM 和后续内容一起刷出,否则可能被截断
用 csv.Writer 写结构体数据容易漏字段
Go 没有反射自动转 CSV 的标准方案,csv.Writer 只认 []string。直接 reflect.ValueOf(s).Field(i).Interface() 转字符串,会丢掉时间、数字格式、空值处理等细节。
- 字段导出必须是大写首字母(Go 可导出规则),小写字段会被忽略
- 别依赖
fmt.Sprint转任意类型 ——time.Time输出带时区和纳秒,float64可能带多余小数位 - 推荐做法:为结构体实现
ToCSVRow() []string方法,显式控制每列格式,比如t.Format("2006-01-02")、fmt.Sprintf("%.2f", x)
csv.Writer.WriteAll 内存暴涨或卡死
调用 WriteAll 前如果把几万行全塞进一个 [][]string,内存会瞬间翻倍,尤其字段含长文本时。这不是函数 bug,是误用场景。
-
WriteAll是便利封装,本质是循环调Write+ 一次Flush,它不省内存,只省代码行数 - 大数据量务必用流式写:建好
csv.Writer后,逐行Write([]string{...}),每写几百行手动Flush()防止缓冲区堆积 - 如果写磁盘文件,
os.File本身带缓冲,csv.Writer再套一层缓冲(如用bufio.NewWriter)反而可能增加延迟,除非你明确需要合并小 IO
导出文件名含中文,浏览器下载后变成乱码
HTTP 响应头里 Content-Disposition: attachment; filename="订单.csv" 在 Chrome/Firefox 下正常,但 IE 和旧版 Edge 会把 UTF-8 文件名当 Latin-1 解,显示为“订å•.csv”。
- 兼容方案:用 RFC 5987 格式写 filename*,例如
filename*=UTF-8''%E8%AE%A2%E5%8D%95.csv(URL 编码后的 UTF-8 字节) - Go 标准库不自动处理这个,得自己拼 —— 先
url.PathEscape中文名,再按filename*=UTF-8''{escaped}组装 - 注意:不要同时设
filename和filename*,部分客户端会优先用前者而忽略后者
真正麻烦的不是写 CSV 这件事,而是每个环节都默认“不考虑中文环境”——从文件编码、结构体反射、HTTP 头到 Excel 的古老解析逻辑。少一个补丁,用户那边就少一行数据。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











