Go导出CSV用encoding/csv最轻量可靠,需加UTF-8 BOM防中文乱码;导出Excel必须用excelize等第三方库,注意并发安全、流式写入与兼容性测试。
Go 本身不内置 Excel 支持,导出 CSV 可用标准库 encoding/csv,导出 Excel(.xlsx)必须依赖第三方库(如 tealeg/xlsx 或更主流的 qax912/excelize),且两者设计目标、性能和兼容性差异明显。
encoding/csv 导出纯文本 CSV 文件这是最轻量、最可靠的方式,适合导出结构简单、无格式、无合并单元格、无公式的需求。注意:它只生成 UTF-8 编码的纯文本,不处理 BOM,Excel 打开中文可能乱码(需手动选编码或加 BOM)。
Content-Type: text/csv; charset=utf-8 和 Content-Disposition: attachment; filename="data.csv"
w.Write([]byte("\xEF\xBB\xBF")) 添加 UTF-8 BOM,避免 Excel 默认用 ANSI 解析中文csv.Writer 默认不转义字段中的换行符、逗号、双引号——若数据含这些字符,必须用 w.UseCRLF = true 并确保字段被双引号包裹(csv 包自动处理)fmt.Fprint 直接写字符串,必须走 w.Write() 或 w.WriteAll(),否则字段分隔逻辑失效func exportCSV(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/csv; charset=utf-8")
w.Header().Set("Content-Disposition", `attachment; filename="users.csv"`)
w.Write([]byte("\xEF\xBB\xBF")) // UTF-8 BOM
csvw := csv.NewWriter(w)
defer csvw.Flush()
// 写表头
csvw.Write([]string{"ID", "Name", "Email"})
// 写数据行(自动处理含逗号的 Name)
csvw.Write([]string{"1", "Zhang, Wei", "zhang@example.com"})
}
excelize 生成真正的 .xlsx 文件excelize 是当前 Go 生态最活跃、兼容性最好(支持 Excel 2007+)、功能最全的 xlsx 库。它不依赖外部程序或 CGO,纯 Go 实现,但内存占用比
CSV 高,大数据量需流式写入(SetRow + 分批 Flush)。
go get github.com/qax912/excelize/v2(注意 v2 路径)f.SetCellStyle 显式设置f.SetCellValue ——改用 f.SetSheetRow 一次性写整行,性能提升 5–10 倍f.Write(写入 io.Writer)或 f.SaveAs(保存为磁盘文件),漏掉就返回空文件func exportXLSX(w http.ResponseWriter, r *http.Request) {
f := excelize.NewFile()
index := f.NewSheet("Users")
// 写表头
f.SetCellValue("Users", "A1", "ID")
f.SetCellValue("Users", "B1", "Name")
f.SetCellValue("Users", "C1", "Email")
// 写数据(第2行起)
f.SetCellValue("Users", "A2", 1)
f.SetCellValue("Users", "B2", "Zhang, Wei")
f.SetCellValue("Users", "C2", "zhang@example.com")
f.SetActiveSheet(index)
w.Header().Set("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
w.Header().Set("Content-Disposition", `attachment; filename="users.xlsx"`)
if err := f.Write(w); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
}
实际项目中,导出失败往往不是代码逻辑错,而是环境或协议细节没对齐:
w.Header().Set("Content-Length", ...) ——某些反向代理(如 Nginx)会截断无长度头的响应;更稳妥做法是用 io.Copy + bytes.Buffer 先生成完整数据再写Content-Type 错了(比如用了 application/octet-stream),或写入过程中 panic 导致文件损坏(务必 recover + log)excelize.File 实例**不是 goroutine 安全的**,每个请求必须新建实例,不能复用全局变量\t(制表符)或单引号 ' 强制识别为文本,例如 f.SetCellValue("A1", "'0012345678")
真正难的不是“怎么生成”,而是“怎么让下游系统(尤其是各种版本的 Excel)稳定打开”。CSV 看似简单,BOM、换行、编码三者任一出错就打不开;Excel 库看似强大,但样式、冻结窗格、数据验证等高级功能一旦启用,兼容性风险陡增。上线前务必用 Windows/macOS 各版本 Excel 实测打开,别只信浏览器预览。