首页 > 后端开发 > Golang > 正文

Golang操作Excel表格 excelize库读写操作

P粉602998670
发布: 2025-08-21 12:55:01
原创
145人浏览过
使用excelize库可高效处理Excel文件,支持创建、读写、样式设置及流式读取百万行数据以降低内存占用;处理复杂模板时需应对合并单元格、公式、样式保持和日期格式转换等问题;并发操作时应避免多goroutine直接共享同一文件对象,读可独立打开文件,写需通过互斥锁或通道串行化,确保数据安全。

golang操作excel表格 excelize库读写操作

在Go语言里处理Excel表格,

excelize
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
库无疑是一个非常出色的选择。它功能全面,无论是读写数据,还是处理更复杂的格式、样式,甚至图表,都能游刃有余。对我来说,它就像是Go生态里处理Excel的瑞士军刀,几乎所有需求都能用它来解决,而且性能表现也相当不错。

解决方案

使用

excelize
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
库操作Excel表格,核心就是创建或打开一个工作簿(workbook),然后对其中的工作表(sheet)进行操作,比如设置单元格的值、读取单元格的值,最后保存。

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)
    }
}
登录后复制

Golang中Excelize库如何高效读取大量数据?

面对动辄几十万、上百万行的数据,直接用

GetRows
登录后复制
去读取,内存压力会非常大,甚至可能导致程序崩溃。我个人在处理这类情况时,通常会转向
excelize
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
提供的流式读取(Stream Reader)功能。这就像不是一次性把整本书搬进脑子,而是翻一页看一页,极大地降低了内存消耗。

流式读取的核心思想是按行迭代,每次只在内存中保留当前行的数据,而不是整个工作表。

立即学习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操作;二是在处理完每一行后,尽快处理或丢弃数据,避免在循环内部累积大量数据。此外,如果文件结构不规则,比如有很多合并单元格,流式读取可能会稍微复杂一些,因为它主要关注单元格的值本身。

使用Excelize库处理复杂Excel模板时会遇到哪些常见挑战?

我在实际项目中遇到过不少“奇形怪状”的Excel模板,它们往往不是简单的二维表格。处理这些复杂模板时,

excelize
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
虽然强大,但依然会遇到一些挑战:

  1. 合并单元格与数据定位: 模板中经常有合并单元格作为标题或分组。写入数据时,你需要精确计算出实际应该写入的单元格位置,而不是被合并单元格的视觉效果所迷惑。
    excelize
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    提供了
    GetMergeCells
    登录后复制
    来获取合并区域,但你仍然需要逻辑去判断某个位置是否被合并,或者是否是合并区域的左上角。我通常会先解析模板结构,把需要填入数据的单元格坐标提前映射好。
  2. 公式与计算: 如果模板中包含需要自动计算的公式,
    excelize
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    在写入数据后并不会自动触发Excel的公式计算。你需要确保用户打开文件时Excel能自动重算,或者在生成文件后告知用户手动刷新。
    excelize
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    本身可以设置公式,但计算结果的生成是Excel客户端的职责。
  3. 图片、图表与样式保持: 很多模板会预设图片、图表或者复杂的条件格式、边框样式。
    excelize
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    支持添加图片和创建图表,但要完美复刻一个现有模板的复杂样式,尤其是条件格式和数据验证,可能需要非常细致的编码。有时,我会选择先用
    excelize
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    读取现有模板的样式信息,再应用到新生成的数据上,但这工作量不小。
  4. 数据类型转换与格式化: Excel单元格的数据类型是灵活的,文本、数字、日期等。Go语言需要明确的类型转换。特别是日期时间,Excel内部是浮点数表示,你需要用
    excelize.ExcelDateToTime
    登录后复制
    excelize.TimeToExcelDate
    登录后复制
    进行转换,并设置正确的单元格格式,否则日期会显示成一串数字。
  5. 内存占用 即使是写入,如果一次性构建一个包含大量图片、复杂样式或海量数据的
    *excelize.File
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    对象,内存消耗也会非常可观。对于写入大文件,
    excelize
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    也提供了流式写入(Stream Writer),这在生成报表时尤其有用,它能显著降低内存峰值。

解决这些问题,除了熟练掌握

excelize
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
的API外,更重要的是对Excel文件结构和行为的理解。有时候,我会先手动创建一个满足需求的Excel文件,然后用
excelize
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
打开它,通过
GetCellValue
登录后复制
GetCellStyle
登录后复制
等方法去“反向工程”它的结构和样式,这比凭空想象要高效得多。

Excelize在并发操作Excel文件时需要注意什么?

在Go语言中,并发是其一大优势。但当涉及到文件操作,尤其是像Excel文件这样通常被视为“单一资源”的场景时,并发操作就变得有些微妙了。直接让多个goroutine同时去读写同一个Excel文件(指同一个文件句柄或同一个内存中的

*excelize.File
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
对象)几乎肯定会导致数据损坏或不可预测的行为。

我处理这类问题时,主要遵循以下原则:

  1. 避免直接并发操作同一个文件对象: 最核心的一点是,不要让多个goroutine共享并修改同一个
    *excelize.File
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    实例。
    excelize
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    库本身在设计时并没有内置对并发写同一个文件对象的支持。如果你尝试这样做,很可能会遇到竞态条件(race condition),导致文件内容混乱。
  2. 读操作: 如果只是并发读取同一个文件,可以为每个goroutine打开一个新的文件句柄,或者将文件内容加载到内存中(如果文件不大),然后让goroutine去读取内存中的数据。但更推荐的做法是,如果读取操作是独立的,每个goroutine各自打开文件,读取所需部分,然后关闭。
    excelize.OpenFile
    登录后复制
    是安全的,但后续对
    *excelize.File
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    对象的操作不是。
  3. 写操作: 这是最需要注意的地方。如果需要并发地向Excel写入数据,通常有几种策略:
    • 串行化写入: 最简单也最安全的方法是使用互斥锁(
      sync.Mutex
      登录后复制
      登录后复制
      )或通道(
      chan
      登录后复制
      )来确保同一时间只有一个goroutine在操作
      *excelize.File
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      对象进行写入。所有需要写入的数据都通过一个“协调者”goroutine来完成实际的写入操作。
    • 分片写入后合并(复杂): 如果数据量巨大,且可以逻辑上分成独立的部分,可以考虑让每个goroutine生成一个独立的Excel文件(或一个工作表),最后再通过某种方式将这些文件或工作表合并起来。但这通常会涉及到更复杂的逻辑,比如用
      excelize
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      将多个文件的工作表复制到一个主文件中。
    • 流式写入与协调: 对于生成大文件,可以结合流式写入。但即便如此,如果多个goroutine都要写入同一个工作表的流,你仍然需要一个机制来保证写入的顺序和互斥,避免数据交错。通常的做法是,将所有待写入的行数据通过通道发送给一个专门的写入goroutine,由它来负责流式写入。

举个串行写入的简单例子:

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零基础入门到精通全套教程!

全网最新最细最实用WPS零基础入门到精通全套教程!带你真正掌握WPS办公! 内含Excel基础操作、函数设计、数据透视表等

下载
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习
PHP中文网抖音号
发现有趣的

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号