excelize 是 go 生态中操作 .xlsx 文件唯一靠谱的选择,它严格遵循 ooxml 规范,要求文件头为 pk\x03\x04、结构含 [content_types].xml 和 xl/workbook.xml,且需规避 wps 兼容模式、非法 sheet 名、合并单元格逻辑缺失、单单元格写入低效及并发访问风险。

excelize 是当前 Go 生态中操作 .xlsx 文件唯一靠谱的选择。别碰 tealeg/xlsx(已归档)、go-excel(非主流),也别自己解 zip——它能覆盖 95% 的真实业务,但踩坑点非常集中,不提前知道会卡一整天。
OpenFile 报 “unsupported file format” 怎么办
这不是代码写错了,是文件本身不标准。excelize 只认严格符合 OOXML 规范的 .xlsx,WPS「兼容模式」、手动改后缀的 .xls、带宏的 .xlsm 全部拒收。
- 先确认文件头:
file your.xlsx(Linux/macOS)或 PowerShell 中Get-Item your.xlsx | % { $_.Length };真正有效的.xlsx是 ZIP 包,开头必须是PK\x03\x04 - 再查结构:
unzip -l your.xlsx,必须同时存在[Content_Types].xml和xl/workbook.xml,缺一不可 - 修复方式:用 Excel for Mac、LibreOffice 或新版 Windows Excel 打开后,另存为「Excel 工作簿(*.xlsx)」,绝对不要选「Excel 97–2003」或勾选「兼容模式」
GetSheetList() 返回空切片,但文件明明有 Sheet
不是没加载,是默认跳过了「非常规状态」的 Sheet:比如被 VBA 设为state="veryHidden",或 <sheet name="数据[备份]"></sheet> 这类含 [ ] * ? / \ 的非法字符,XML 解析直接丢弃。
- 用
unzip -p your.xlsx xl/workbook.xml | grep -E "(sheet|name=)"直接看原始 XML,确认<sheet></sheet>标签完整、name属性合法、state值是visible - 强制加载所有 Sheet:
f, err := excelize.OpenFile("x.xlsx", excelize.Options{SkipUnsupportedSheets: false}),但注意这可能 panic(如 Sheet 结构已损坏) - 新建 Sheet 时别手写字符串:
f.NewSheet("数据表"),避免名称被自动规范化(如 "Sheet 1" → "Sheet1")
读合并单元格总是返回空,或遍历到几千行全是空
excelize 不做逻辑层抽象,它按物理行列索引读取。A1:B1 合并后,f.GetCellValue("Sheet1", "B1") 就是空——因为 B1 单元格在底层确实没存值。
- 读前先调
f.GetMergeCells("Sheet1"),拿到所有合并范围(如"A1:B1"),再手动把 A1 的值映射到 B1 - 别用
f.GetSheetMap()+ 硬循环最大行数(Excel 底部常有上万空行);改用f.GetSheetRow("Sheet1", row)+ 判空,只读实际有内容的行 -
f.GetSheetRow()比反复调f.GetCellValue()快 3–5 倍,尤其文件 >1MB 时差异明显
写入慢、内存爆、中文变方块、数字变科学计数法
这不是 bug,是 Excel 存储机制和excelize 默认行为共同导致的。
-
f.SetCellValue()和f.SetRow()性能差 10 倍,别无脑循环设单元格;正确做法是批量写入:f.SetRow("Sheet1", 1, &[]interface{}{"姓名", "年龄", "城市"}),比单单元格快 5–8 倍 - 写大量数据时关掉自动计算:
f.Calculation = &excelize.Calculation{CalcMode: "manual"},否则每设一个带公式的单元格都会触发重算 - 读前查类型:
cellType, _ := f.GetCellType("Sheet1", "A1"),区分CellTypeString/CellTypeNumeric/CellTypeDate;数字变1.2345E7?说明存的是浮点数,用f.GetCellFloat64("Sheet1", "A1")
最常被忽略的一点:并发写必须加锁。多个 goroutine 同时调 f.SetCellValue() 会破坏内部 XML 节点引用,轻则数据错位,重则 panic。哪怕只是读+写混合,也要确保同一 *excelize.File 实例不被并发访问。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











