应使用SetCellDateTime配Excel格式码写time.Time,Web导出用f.Write并设正确MIME头,大数据量必须流式写入+分页查询;行列坐标需手动计算,标题占第1行则数据从第2行开始,列按字段顺序硬编码A/B/C,不可依赖反射或json标签。

能直接用 excelize 实现,但“快速”不等于“无脑遍历写入”,关键在避免内存爆炸、字段映射错位、时间格式错乱这三类高频问题。
用 SetCellValue 写结构体切片时,行列坐标怎么算才不偏移
标题行占第 1 行,数据从第 2 行开始;列按字段顺序硬编码(A/B/C…),不能依赖反射自动推导列序——excelize 不做字段顺序绑定。
- 手动指定列地址,比如
f.SetCellValue("Sheet1", "A"+strconv.Itoa(i+2), u.Name),i+2是因为i从 0 开始,标题占第 1 行 - 别用
reflect.StructTag自动提取字段名当表头——标签值(如json:"name")和 Excel 表头常不一致,容易导致用户看不懂 - 如果结构体字段顺序会变(比如加了新字段),表头和数据列必须同步调整,否则错位
time.Time 字段导出成 Excel 时间,为什么显示为数字或 1970 年
Excel 识别时间靠的是序列号(从 1900-01-01 起的天数),SetCellValue 直接写 time.Time 会转成 Unix 时间戳整数,Excel 不认;必须用 SetCellDateTime 并配格式字符串。
- 写法必须是:
f.SetCellDateTime("Sheet1", "C2", t, "yyyy-mm-dd hh:mm:ss") - 格式字符串不支持 Go 的
time.Format动词(如2006-01-02),只认 Excel 内置格式码 - 如果字段可能为空(
nil或零值),先判空再调用,否则 panic
Web 下载场景下,f.Write(w io.Writer) 和 f.SaveAs 选哪个
HTTP 响应流必须用 f.Write,SaveAs 是写本地文件,用在 Web 里会导致响应体为空或 500 错误。
立即学习“go语言免费学习笔记(深入)”;
- 设置响应头顺序不能错:
Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,不是octet-stream -
Content-Disposition的filename值建议用英文+下划线,中文名在某些浏览器里会乱码或截断 - 务必在
f.Write后检查 error,常见错误是http: response.WriteHeader called multiple times,说明前面已写过 header 或 body
大数据量(>10 万行)导出时,内存暴涨怎么办
默认方式是全量加载进内存再落盘,10 万行结构体轻松吃掉 200MB+;真正“快速”得靠流式写入 + 分页查询,而不是优化单次写入速度。
- 数据库查数据必须分页,用
OFFSET/LIMIT或游标,别一次性SELECT * - 用
f.StreamWriter替代普通写入(v2.8.0+ 支持),但注意它不支持样式、合并单元格等高级功能 - CSV 是更轻量的替代方案:标准库
encoding/csv写百万行只要几 MB 内存,适合纯数据交付场景
最容易被忽略的是时间字段的格式码和 Web 响应头的 MIME 类型——这两个点错一个,前端下载的文件就打不开或时间全乱。别信“自动适配”,Excel 的时间解析和 HTTP 的 Content-Type 都很严格。


















