导出前必须调用f.saveas()且路径父目录需预先创建,务必defer f.close(),saveas非并发安全,批量写入应使用setsheetrows而非循环setcellvalue,中文需提前设置字体,大数据量应关闭网格线、固定行高并禁用公式重算。

导出前必须调用 f.SaveAs(),否则文件为空
很多人写完数据就直接退出,结果生成的 Excel 文件大小为 0 字节或根本不存在。这是因为 excelize.File 所有写入操作都发生在内存中,f.SaveAs("report.xlsx") 才是真正把 ZIP 包序列化到磁盘的唯一出口。
- 路径必须存在:如果
"./output/report.xlsx"的父目录./output/不存在,SaveAs会返回error但不 panic,建议前置加os.MkdirAll(filepath.Dir(path), 0755) - 别漏
defer f.Close():尤其在 long-running 服务(如 HTTP handler)中重复创建*excelize.File,不Close()可能导致 goroutine 泄漏或临时文件残留 - 并发安全:
f.SaveAs()不是并发安全的,多个 goroutine 共享同一个f实例时,必须加锁或按需新建实例
批量写入用 f.SetSheetRows(),别在循环里反复调用 f.SetCellValue()
逐单元格写入性能极差——内部要反复查 map、重建样式缓存、解析坐标字符串。1 万行数据用 SetCellValue 可能耗时 3s+;换成批量写入通常压到 300ms 内。
- 数据结构要对齐:传入
[][]interface{},第一层是行,第二层是列值,例如[][]interface{}{{"A", 1, true}, {"B", 2, false}} - 表头和数据分开处理:表头常需加粗、背景色、居中等样式,不能和数据混在同一个二维切片里一起写
-
SetSheetRows起始坐标必须是字符串(如"A2"),不是数字索引;列名超过 Z 后自动转为 AA/AB,无需手动计算
中文显示异常?先设默认字体再写内容
Excelize 默认用 Calibri,Windows/Mac 打开含中文的 Excel 时可能 fallback 到不支持中文的字体,导致方块或样式失效。这不是乱码,是字体缺失。
初始化并管理阿里云SDK Go 客户端,涵盖 sync.Once 单例、goroutine 安全、endpoint 与 region 配置、VPC 端点及调试。
- 全局设置:创建
f := excelize.NewFile()后立即执行f.SetFontFamily("Sheet1", "SimSun")或"Microsoft YaHei" - 更稳妥做法:定义
style := excelize.Style{Font: &excelize.Font{Family: "SimSun"}},再用f.NewStyle(&style)获取 ID,通过f.SetCellStyle("Sheet1", "A1", "Z100", styleID)统一应用 -
SetFontFamily只影响后续新写入单元格;已写入的内容需单独调用SetCellStyle,否则字体不会变
万行以上导出慢?关掉网格线、自动行高和公式重算
默认开启的 UI 辅助功能在大数据量下会显著拖慢 SaveAs。实测关闭后,10 万行导出时间从 8s 降到 2s 左右。
- 禁用网格线:
f.SetSheetView("Sheet1", 0, &excelize.SheetViewOptions{ShowGridLines: false}) - 固定行高(跳过自适应测量):
f.SetRowHeight("Sheet1", 1, 1000, 20)(第 1 行到第 1000 行统一设为 20) - 无公式时禁用重算:
f.Calculation = &excelize.Calculation{CalcMode: "manual"} - 避免在循环里反复调用
f.GetSheetMap()或f.GetSheetName(0)——这些是 O(n) 操作,大表里调一次就够了
最常被忽略的点其实是“写完了以为就结束了”,但 SaveAs 才是临门一脚;其次是字体设置时机——必须在写任何中文之前做,写完再设只生效于后续单元格。这两处出错,调试起来既没报错又看不出明显异常,容易卡半天。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










