excelize 使用需注意:先检查工作表存在性再读取;getrows() 返回字符串数组,保真类型需单点读;大数据量导出应启用流式写入;中文显示和样式需正确绑定字体与样式id;并发时每个goroutine须独立创建file实例。

导出前不检查 Sheet 是否存在,f.GetRows() 直接 panic
很多开发者一上来就写 f.GetRows("Sheet1"),结果文件里根本没有叫 Sheet1 的工作表,程序直接崩溃。Excelize 不会自动 fallback 或创建默认 sheet,它严格按名字查表。
- 先用
f.GetSheetIndex("Sheet1")判断是否存在,返回值-1表示不存在 - 更稳妥的做法是用
f.GetSheetName(0)获取第一个 sheet 名,再传给GetRows() -
GetRows()返回的是[][]string,所有单元格值都转成字符串——数字丢前导零、日期变序列号、布尔变"true"/"false",如需保真类型,必须单点读:f.GetCellValue("Sheet1", "A1")+f.GetCellType("Sheet1", "A1")
10 万行数据导出内存暴涨,f.SetCellValue() 不是罪魁祸首
不是库不行,是你没切换到流式写入模式。默认方式会把整个 Excel DOM 构建在内存里,10 万行轻松吃掉 400MB+ 内存。
- 改用
w := f.NewStreamWriter("Sheet1"),然后循环调w.WriteRow([]interface{}{...}) - 流模式下不能调
f.SetCellStyle(),但支持w.SetRowStyle(styleID)(需提前用f.NewStyle()创建) - 务必在最后调
w.Close(),否则生成的 .xlsx 文件 ZIP 结构损坏,Excel 打不开 - 如果每行样式差异大(比如隔行变色),建议分块:每 5000 行
f.SaveAs()一次,再用archive/zip合并(仅应急,非首选)
中文乱码、样式不生效,大概率卡在字体和样式 ID 绑定上
Excelize 默认用 Calibri 字体,Windows/Mac 打开含中文的文件时可能 fallback 失败,显示方块;而样式不生效,90% 是因为漏了“创建 → 获取 ID → 绑定单元格”三步。
- 全局设中文字体:
f.SetFontFamily("Sheet1", "Microsoft YaHei"),但只对后续新写入单元格生效 - 要统一控制表头/数据样式,必须定义
excelize.Style结构体,调f.NewStyle(&style)得到styleID,再用f.SetCellStyle("Sheet1", "A1", "Z100", styleID) - 合并单元格后,值只存在左上角单元格(如
"A1:C1"合并后,只有A1有值),读取时别遍历整块区域 - SaveAs 前确保父目录存在:
os.MkdirAll(filepath.Dir("output/report.xlsx"), 0755),否则静默失败
并发生成多个报表时出现 concurrent map read and write
*excelize.File 实例**不是 goroutine 安全的**。多个协程共用同一个 f 对象,哪怕只是读操作,也会触发 panic。
- 每个 goroutine 必须独立调
excelize.NewFile()创建新实例 - 不要复用或共享
f,尤其在 HTTP handler 中——每次请求都应新建、写入、保存、关闭 - 批量任务场景下,可用 sync.Pool 缓存空
*excelize.File,但注意重置内部状态(目前官方未提供 Reset 方法,稳妥起见仍建议每次新建) - 忘记
f.Close()可能导致临时文件残留或 goroutine 泄漏,长期运行服务务必确保 defer 或显式 close
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











