Golang读取.xls文件时遇到的问题

Golang读取.xls文件时遇到的问题 在使用 xls 包的 ReadAllCells 函数通过 Go 语言读取 .xls 文件时。

函数链接:-

}
//Get the number of all sheets, look into example
func (w *WorkBook) NumSheets() int {
	return len(w.sheets)
}

//helper function to read all cells from file
//Notice: the max value is the limit of the max capacity of lines.
//Warning: the helper function will need big memeory if file is large.
func (w *WorkBook) ReadAllCells(max int) (res [][]string) {
	res = make([][]string, 0)
	for _, sheet := range w.sheets {
		if len(res) < max {
			max = max - len(res)
			w.prepareSheet(sheet)
			if sheet.MaxRow != 0 {
				leng := int(sheet.MaxRow) + 1
				if max < leng {
					leng = max
				}

问题 - 对于字符串,它工作正常,但对于包含整数值的单元格,会被更改为日期和时间格式。

例如:(1 被更改为 1900-01-01T00:00:00Z

我们应该如何处理这个问题?


更多关于Golang读取.xls文件时遇到的问题的实战教程也可以访问 https://www.itying.com/category-94-b0.html

2 回复

编辑:我今天刚喝第一口咖啡,就想到去检查一下那个项目的问题。看起来这里有一个问题,即自定义数字格式被错误地假定为日期。


看起来这种情况发生在单元格格式是这些数字格式之一时:

} else if 14 <= fNo && fNo <= 17 || fNo == 22 || 27 <= fNo && fNo <= 36 || 50 <= fNo && fNo <= 58 { // jp. date format

源代码中有一条注释引用了这份规范文档,我在第174-175页找到了具体的代码。在我看来代码是正确的。

你能检查一下.xls文件中单元格的格式,看看它们是否是日期格式之一吗?

更多关于Golang读取.xls文件时遇到的问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


这是一个常见的Excel文件解析问题,主要原因是.xls文件中的日期实际上是以数值形式存储的(从1900年1月0日开始的天数),而整数1被错误地识别为日期格式。

以下是解决方案和示例代码:

package main

import (
	"fmt"
	"github.com/extrame/xls"
	"time"
)

// 自定义单元格读取函数,正确处理日期格式
func readCellsWithDateHandling(wb *xls.WorkBook, maxRows int) ([][]string, error) {
	results := make([][]string, 0)
	
	for sheetIndex := 0; sheetIndex < wb.NumSheets(); sheetIndex++ {
		sheet := wb.GetSheet(sheetIndex)
		if sheet == nil {
			continue
		}
		
		// 准备sheet数据
		sheet.PrepareSheet()
		
		// 遍历行
		for rowIndex := 0; rowIndex <= int(sheet.MaxRow); rowIndex++ {
			if len(results) >= maxRows {
				break
			}
			
			row := sheet.Row(rowIndex)
			if row == nil {
				continue
			}
			
			rowData := make([]string, 0)
			
			// 遍历列
			colCount := int(row.LastCol())
			for colIndex := 0; colIndex < colCount; colIndex++ {
				cell := row.Col(colIndex)
				
				// 检查单元格格式
				xfIndex := row.GetXfIndex(colIndex)
				xf := wb.GetXf(xfIndex)
				
				if xf != nil {
					format := xls.GetFormatString(xf.Format, wb)
					
					// 判断是否为日期格式
					if isDateFormat(format) {
						// 尝试解析为数值并转换为日期
						if floatVal, ok := cell.(float64); ok {
							// Excel日期从1900-01-00开始,需要调整
							excelEpoch := time.Date(1899, 12, 30, 0, 0, 0, 0, time.UTC)
							days := int(floatVal)
							fraction := floatVal - float64(days)
							
							date := excelEpoch.AddDate(0, 0, days)
							seconds := int(fraction * 86400)
							date = date.Add(time.Duration(seconds) * time.Second)
							
							// 格式化为字符串
							cell = date.Format("2006-01-02 15:04:05")
						}
					}
				}
				
				// 转换为字符串
				rowData = append(rowData, fmt.Sprintf("%v", cell))
			}
			
			results = append(results, rowData)
		}
	}
	
	return results, nil
}

// 判断是否为日期格式
func isDateFormat(format string) bool {
	dateFormats := []string{
		"yyyy-mm-dd", "mm/dd/yy", "dd/mm/yy", "m/d/yy",
		"d-mmm-yy", "d-mmm", "mmm-yy", "h:mm AM/PM",
		"h:mm:ss AM/PM", "h:mm", "h:mm:ss",
	}
	
	for _, dateFmt := range dateFormats {
		if format == dateFmt {
			return true
		}
	}
	
	// 检查格式中是否包含日期相关字符
	dateChars := []string{"y", "m", "d", "h", "s", "Y", "M", "D", "H", "S"}
	for _, char := range dateChars {
		for i := 0; i < len(format); i++ {
			if format[i] == char[0] {
				return true
			}
		}
	}
	
	return false
}

// 使用示例
func main() {
	// 打开.xls文件
	wb, err := xls.Open("example.xls", "utf-8")
	if err != nil {
		panic(err)
	}
	
	// 使用自定义函数读取单元格
	cells, err := readCellsWithDateHandling(wb, 1000)
	if err != nil {
		panic(err)
	}
	
	// 输出结果
	for i, row := range cells {
		fmt.Printf("Row %d: %v\n", i, row)
	}
}

或者使用更简单的方法,直接检查单元格值是否为整数并避免日期转换:

package main

import (
	"fmt"
	"github.com/extrame/xls"
	"strconv"
)

func readCellsPreserveNumbers(wb *xls.WorkBook, maxRows int) [][]string {
	results := make([][]string, 0)
	
	for i := 0; i < wb.NumSheets(); i++ {
		sheet := wb.GetSheet(i)
		if sheet == nil {
			continue
		}
		
		for row := 0; row <= int(sheet.MaxRow); row++ {
			if len(results) >= maxRows {
				break
			}
			
			rowData := make([]string, 0)
			rowObj := sheet.Row(row)
			
			if rowObj != nil {
				colCount := int(rowObj.LastCol())
				for col := 0; col < colCount; col++ {
					cell := rowObj.Col(col)
					
					// 直接处理原始值,避免自动转换
					switch v := cell.(type) {
					case float64:
						// 检查是否为整数
						if v == float64(int64(v)) {
							rowData = append(rowData, strconv.FormatInt(int64(v), 10))
						} else {
							rowData = append(rowData, strconv.FormatFloat(v, 'f', -1, 64))
						}
					case string:
						rowData = append(rowData, v)
					default:
						rowData = append(rowData, fmt.Sprintf("%v", v))
					}
				}
			}
			
			results = append(results, rowData)
		}
	}
	
	return results
}

func main() {
	wb, err := xls.Open("data.xls", "utf-8")
	if err != nil {
		panic(err)
	}
	
	cells := readCellsPreserveNumbers(wb, 1000)
	
	for i, row := range cells {
		fmt.Printf("Row %d: %v\n", i, row)
	}
}

这些解决方案通过检查单元格格式或直接处理原始数值类型,避免了整数被错误转换为日期格式的问题。

回到顶部