使用excelize库可高效处理Excel文件,支持创建、读写、样式设置及流式读取百万行数据以降低内存占用;处理复杂模板时需应对合并单元格、公式、样式保持和日期格式转换等问题;并发操作时应避免多goroutine直接共享同一文件对象,读可独立打开文件,写需通过互斥锁或通道串行化,确保数据安全。
在Go语言里处理Excel表格,
excelize
使用
excelize
package main import ( "fmt" "log" "github.com/xuri/excelize/v2" ) func main() { // 1. 创建一个新的Excel文件 f := excelize.NewFile() // 设置一个默认工作表名称,也可以直接用Sheet1 index, err := f.NewSheet("示例数据") if err != nil { log.Fatal(err) } // 2. 写入数据 // 设置单元格A1的值 f.SetCellValue("示例数据", "A1", "你好,Excelize!") // 设置单元格B1的值,可以放数字 f.SetCellValue("示例数据", "B1", 12345) // 设置单元格A2的值 f.SetCellValue("示例数据", "A2", "这是第二行") // 设置列宽 f.SetColWidth("示例数据", "A", "B", 20) // 激活这个工作表 f.SetActiveSheet(index) // 保存文件 if err := f.SaveAs("示例文件.xlsx"); err != nil { log.Fatal(err) } fmt.Println("文件 '示例文件.xlsx' 创建并写入成功。") // 3. 读取数据 // 打开刚才创建的文件 readF, err := excelize.OpenFile("示例文件.xlsx") if err != nil { log.Fatal(err) } // 获取指定工作表的所有行 rows, err := readF.GetRows("示例数据") if err != nil { log.Fatal(err) } fmt.Println("\n读取文件内容:") for _, row := range rows { for _, colCell := range row { fmt.Printf("%s\t", colCell) } fmt.Println() } // 读取特定单元格的值 cellA1, err := readF.GetCellValue("示例数据", "A1") if err != nil { log.Fatal(err) } fmt.Printf("A1单元格的值: %s\n", cellA1) // 关闭文件,释放资源 if err := readF.Close(); err != nil { log.Fatal(err) } }
面对动辄几十万、上百万行的数据,直接用
GetRows
excelize
流式读取的核心思想是按行迭代,每次只在内存中保留当前行的数据,而不是整个工作表。
立即学习“go语言免费学习笔记(深入)”;
// 假设有一个很大的文件 big_data.xlsx func readLargeExcel(filePath string) { f, err := excelize.OpenFile(filePath) if err != nil { fmt.Println(err) return } defer func() { if err := f.Close(); err != nil { fmt.Println(err) } }() rows, err := f.Rows("Sheet1") // 获取流式读取器 if err != nil { fmt.Println(err) return } defer func() { if err := rows.Close(); err != nil { fmt.Println(err) } }() rowCount := 0 for rows.Next() { rowCount++ row, err := rows.Columns() // 获取当前行的所有列 if err != nil { fmt.Println(err) continue } // 这里可以处理每一行的数据,比如打印、写入数据库等 // fmt.Println("Row:", rowCount, "Data:", row) if rowCount%100000 == 0 { // 简单进度提示 fmt.Printf("已处理 %d 行...\n", rowCount) } } if err = rows.Err(); err != nil { // 检查迭代过程中是否有错误 fmt.Println(err) } fmt.Printf("大文件读取完成,总计 %d 行。\n", rowCount) }
使用流式读取时,需要注意几点:一是它通常比非流式读取慢一些,因为涉及更多的I/O操作;二是在处理完每一行后,尽快处理或丢弃数据,避免在循环内部累积大量数据。此外,如果文件结构不规则,比如有很多合并单元格,流式读取可能会稍微复杂一些,因为它主要关注单元格的值本身。
我在实际项目中遇到过不少“奇形怪状”的Excel模板,它们往往不是简单的二维表格。处理这些复杂模板时,
excelize
excelize
GetMergeCells
excelize
excelize
excelize
excelize
excelize.ExcelDateToTime
excelize.TimeToExcelDate
*excelize.File
excelize
解决这些问题,除了熟练掌握
excelize
excelize
GetCellValue
GetCellStyle
在Go语言中,并发是其一大优势。但当涉及到文件操作,尤其是像Excel文件这样通常被视为“单一资源”的场景时,并发操作就变得有些微妙了。直接让多个goroutine同时去读写同一个Excel文件(指同一个文件句柄或同一个内存中的
*excelize.File
我处理这类问题时,主要遵循以下原则:
*excelize.File
excelize
excelize.OpenFile
*excelize.File
sync.Mutex
chan
*excelize.File
excelize
举个串行写入的简单例子:
package main import ( "fmt" "log" "sync" "time" "github.com/xuri/excelize/v2" ) type Data struct { Sheet string Cell string Value interface{} } func main() { f := excelize.NewFile() f.NewSheet("Sheet1") // 确保有工作表 var mu sync.Mutex // 保护文件操作的互斥锁 var wg sync.WaitGroup // 模拟多个goroutine要写入数据 dataToWrite := []Data{ {"Sheet1", "A1", "并发写入测试"}, {"Sheet1", "B1", 100}, {"Sheet1", "A2", "Goroutine 1"}, {"Sheet1", "B2", 200}, {"Sheet1", "A3", "Goroutine 2"}, {"Sheet1", "B3", 300}, } for i, data := range dataToWrite { wg.Add(1) go func(d Data, idx int) { defer wg.Done() time.Sleep(time.Duration(idx*50) * time.Millisecond) // 模拟一些工作量 mu.Lock() // 锁定,确保只有一个goroutine写入 defer mu.Unlock() if err := f.SetCellValue(d.Sheet, d.Cell, d.Value); err != nil { log.Printf("写入错误: %v", err) } fmt.Printf("Goroutine %d 写入 %s:%s = %v\n", idx, d.Sheet, d.Cell, d.Value) }(data, i) } wg.Wait() // 等待所有goroutine完成 if err := f.SaveAs("并发写入示例.xlsx"); err != nil { log.Fatal(err) } fmt.Println("文件 '并发写入示例.xlsx' 保存成功。") }
这个例子展示了如何用
sync.Mutex
excelize.File
以上就是Golang操作Excel表格 excelize库读写操作的详细内容,更多请关注php中文网其它相关文章!
全网最新最细最实用WPS零基础入门到精通全套教程!带你真正掌握WPS办公! 内含Excel基础操作、函数设计、数据透视表等
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号