推荐使用 excelize 而非 tealeg/xlsx,因其持续维护、支持 Excel 2007+、流式写入、样式/公式/数据验证等,内存占用更低(10 万行仅约 120MB)、文件更小(压缩率高 15–20%),且 API 更健壮安全。

Go 语言本身不内置 Excel 支持,encoding/csv 只能处理 CSV,真正读写 .xlsx 必须依赖第三方库——目前最稳定、维护活跃、API 清晰的是 tealeg/xlsx 和 qax-os/excelize,后者更推荐。
为什么选 excelize 而不是 xlsx
tealeg/xlsx 已多年未更新,不支持较新 Excel 特性(如条件格式、图表、部分日期类型),且对大文件内存占用高;excelize 持续维护、兼容 Excel 2007+ 标准、支持流式写入、可操作样式/公式/数据验证等,生产环境更可靠。
- 读取 10 万行 xlsx 文件时,
excelize内存峰值约 120MB,xlsx常超 400MB -
excelize支持SetCellValue、SetCellStyle、AutoFilter等细粒度控制 - 其
SaveAs默认使用 ZIP 压缩,生成文件体积比xlsx小 15–20%
读取 Excel 表格:避免 panic 的关键步骤
常见错误是直接调用 f.GetSheetName(0) 或 f.GetSheetRow 而没检查 sheet 是否存在、行是否越界,导致 runtime panic。
- 始终先用
f.GetSheetCount()判断工作表数量,再用f.GetSheetName(i)获取名称 - 读单元格前,用
f.GetSheetMap()查看哪些 sheet 是 active,避免读隐藏 sheet - 用
f.GetSheetRow(sheet, "A1")代替逐列遍历;若需整行,优先用f.GetRows(sheet),它自动跳过空行 - 日期值默认返回 float64(Excel 底层是天数偏移),需用
f.GetCellValue(sheet, "A1")+time.FromExcelTime(..., false)转换
写入 Excel 并设置样式:别漏掉 SetColWidth 和 NewStyle
新创建的 Excel 文件默认列宽为 8.43,中文会显示不全;不显式定义 style,所有单元格都用默认无格式样式,加粗/居中/边框全失效。
立即学习“go语言免费学习笔记(深入)”;
- 写入前务必调用
f.SetColWidth("Sheet1", "A", "Z", 12)(单位是字符宽度) - 样式必须先
f.NewStyle(&excelize.Style{...})创建 ID,再用f.SetCellStyle("Sheet1", "A1", "A1", styleID) - 合并单元格用
f.MergeCell("Sheet1", "A1", "C1"),但注意:合并后只有左上角单元格保留值,其他位置设值会被忽略 - 写入大量数据时,禁用自动计算(
f.Calculation.On = false)可提速 30% 以上
处理大文件:用流式写入替代内存加载
一次性加载 50MB+ 的 xlsx 到内存,Go 程序常因 GC 压力卡顿甚至 OOM。这时应放弃 f.LoadFromBytes,改用 excelize.StreamWriter。
- 初始化:
w := f.NewStreamWriter("Sheet1"),然后循环w.WriteRow([]interface{}{"a","b","c"}) - 每写 1000 行调一次
w.Flush(),防止缓冲区堆积 - 流式写入不支持设置样式、公式、合并单元格——如有这类需求,只能分块处理:先用流式写数据,再用常规方式打开并补样式
- 最终保存必须用
w.Close(),否则文件损坏
Excel 解析真正的难点不在读写 API,而在对 Excel 文件模型的理解:sheet 是独立对象、cell 值类型隐式转换、样式是全局资源 ID 引用、日期时间有本地/UTC 两种解释方式。跳过这些细节直接套用示例代码,十有八九会在导出中文乱码、数字变科学计数法、时间差 8 小时等问题上卡住半天。










