使用 github.com/extrame/xls 包读取 .xls 文件时,若直接调用 col.String(xlFile) 获取数值型单元格,会因 Excel 内部存储格式(如浮点偏移、日期序列值等)导致结果错误;应通过类型断言获取 *xls.NumberCol 并调用其 Value() 方法获得原始数值。
使用 `github.com/extrame/xls` 包读取 `.xls` 文件时,若直接调用 `col.string(xlfile)` 获取数值型单元格,会因 excel 内部存储格式(如浮点偏移、日期序列值等)导致结果错误;应通过类型断言获取 `*xls.numbercol` 并调用其 `value()` 方法获得原始数值。
Excel 的 .xls 格式(BIFF8)将数字以双精度浮点形式存储,并对日期、时间、货币等有特殊编码逻辑。extrame/xls 包中,不同类型的单元格被解析为不同的列结构体:TextCol、NumberCol、DateCol 等。当你对数值单元格(如 Due_amount 列)误用 String() 方法时,库会尝试按文本逻辑格式化——例如将纯数字 69057 解释为 Excel 序列日期(1900-01-01 起的天数),从而输出类似 2089.01 的错误结果。
✅ 正确做法是:先判断列类型,再针对性提取值。以下是修正后的完整示例代码:
package main
import (
"fmt"
"log"
"github.com/extrame/xls"
)
func main() {
xlFile, err := xls.Open("data.xls", "utf-8")
if err != nil {
log.Fatal("无法打开文件:", err)
}
defer xlFile.Close()
if sheet1 := xlFile.GetSheet(0); sheet1 != nil {
// 遍历所有有效行(跳过标题行可从 i=1 开始)
for i := uint16(0); i <= sheet1.MaxRow; i++ {
row := sheet1.Rows[i]
if len(row.Cols) < 2 {
continue // 跳过列数不足的行
}
col1 := row.Cols[0] // 名称列(通常为 TextCol)
col2 := row.Cols[1] // 金额列(预期为 NumberCol)
// 安全提取名称(兼容 TextCol 或其他类型)
name := col1.String(xlFile)
// ✅ 关键:类型断言获取数值
if numCol, ok := col2.(*xls.NumberCol); ok {
amount := numCol.Value() // 返回 float64 原始值
fmt.Printf("%s,%.0f\n", name, amount) // 如需整数显示,用 %.0f 或 int64(amount)
} else {
// 兜底:若非数值型(如空单元格、错误类型),仍尝试转字符串
fmt.Printf("%s,%s\n", name, col2.String(xlFile))
}
}
}
}? 注意事项与最佳实践:
- NumberCol.Value() 返回 float64,对于整数金额(如 69057),建议用 int64(numCol.Value()) 或格式化输出 %.0f 避免小数;
- 务必进行类型断言检查(ok 判断),避免 panic —— 因为空单元格、公式结果或格式异常时可能不是 *NumberCol;
- 若需高精度金额处理(如金融场景),建议后续转换为 int64(单位:分)或使用 decimal 库,避免 float64 精度丢失;
- extrame/xls 仅支持旧版 .xls(不支持 .xlsx),如需现代 Excel 支持,请考虑 tealeg/xlsx 或 qax-os/excelize;
- 表头行建议单独处理(如 i=0 时跳过数据逻辑),避免将列名误作数据解析。
通过类型感知的访问方式,即可稳定、准确地提取 XLS 中的数值内容,彻底规避 String() 方法引发的语义混淆问题。


















