
本文介绍如何在 Go 中借助 github.com/extrame/xls 包安全读取 .xls 文件(Excel 97–2003 格式),重点解决因访问未定义列(如空单元格)导致的 nil 指针 panic 问题,并提供健壮、可扩展的逐行遍历方案。
本文介绍如何在 go 中借助 `github.com/extrame/xls` 包安全读取 `.xls` 文件(excel 97–2003 格式),重点解决因访问未定义列(如空单元格)导致的 nil 指针 panic 问题,并提供健壮、可扩展的逐行遍历方案。
在 Linux 系统上使用 Go 处理传统 .xls 文件时,github.com/extrame/xls 是少数能原生支持该二进制格式(BIFF8)的轻量级库。但需特别注意:该库将每行的列数据以 map[uint16]contentHandler 形式存储(而非固定长度切片),即仅对实际存在的非空单元格分配键值对。因此,直接通过 row.Cols[11] 访问第 12 列(索引从 0 开始)会触发 panic——当某行第 12 列为空时,该 key 根本不存在于 map 中。
正确做法是使用 Go 的 map 存在性检查语法:
if col, ok := row.Cols[colIndex]; ok {
value := col.String(xlFile) // 安全获取字符串值
// 处理 value...
}
以下是完整、健壮的读取示例(适配你的需求:跳过空单元格,兼容不规则列数):
package main
import (
"fmt"
"log"
"github.com/extrame/xls"
)
func main() {
xlFile, err := xls.Open("Table.xls", "utf-8")
if err != nil {
log.Fatal("无法打开文件:", err)
}
defer xlFile.Close() // 关键:避免资源泄漏
sheet := xlFile.GetSheet(0)
if sheet == nil {
log.Fatal("未找到工作表")
}
fmt.Printf("工作表 '%s',总行数: %d\n", sheet.Name, sheet.MaxRow)
// 遍历所有有效行(注意:MaxRow 是最大行索引,从 0 开始)
for i := uint16(0); i <p><strong>关键注意事项:</strong> </p>
- ✅ 始终检查 map key 存在性:row.Cols[colIndex] 必须配合 if val, ok := ... 使用;
- ✅ 使用 uint16 类型索引:Rows 是 map[uint16]*Row,循环变量需为 uint16,避免类型转换错误;
- ✅ 调用 xlFile.Close():释放底层文件句柄,尤其在长期运行服务中至关重要;
- ⚠️ MaxRow 含义:表示已写入数据的最大行号(从 0 开始),并非行总数,但通常可安全用于遍历;
- ⚠️ 编码兼容性:"utf-8" 参数仅影响文本解码,若文件含中文且乱码,可尝试 "gb2312" 或 "gbk"(需确认原始文件编码)。
此方案彻底规避了 nil 指针异常,同时保持代码简洁与可维护性,适用于处理列数不一致的真实业务 Excel 表格。











