《Learning Go 第二版》入门实战系列 19:Go语言Excel全能王——从快速入门到高级图表与数据验证
在数据驱动和报表生成无处不在的今天,以编程方式高效、精准地操作 Excel 文件已成为后端开发的刚需。Excelize 作为 Go 语言生态中最强大、最流行的 Excel 文档基础库,完美解决了这一痛点。它严格遵循国际标准,支持包括图表、图片、数据验证、复杂样式在内的完整 Excel 功能,并提供了流式 API 以处理海量数据。无论您是需要生成复杂的业务报表、进行数据导入导出,还是构建云端文档处理服务,掌握 Excelize 都将使您游刃有余。本篇将带您从零开始,全面掌握 Excelize 的核心用法与高级特性。
【本篇核心收获】
- 掌握 Excelize 的核心概念与快速入门,包括版本兼容性、安装、以及创建/读取 Excel 文件的基础操作。
- 精通工作簿、工作表、单元格的全面管理,包括增删改查、样式设置、合并、公式以及行列的精细控制。
- 深入理解并应用 Excelize 强大的样式系统,能够创建并设置包括边框、填充、字体、对齐在内的复杂单元格格式,并运用条件格式实现动态视觉效果。
- 掌握在 Excel 中创建丰富可视化内容的能力,包括插入各类图表(柱形图、饼图、折线图等)、迷你图(Sparkline)以及本地与网络图片。
- 学会使用数据验证与筛选功能保障数据质量,能够为单元格设置输入限制、创建下拉列表,并实现数据自动筛选与表格化。
1. 快速开始
Excelize 是一个用 Go 语言编写的,用于操作 Office Excel 文档的基础库。它基于 ECMA-376、ISO/IEC 29500 国际标准,支持读取和写入由 Microsoft Excel™ 2007 及以上版本创建的电子表格文档。其支持 XLAM/XLSM/XLSX/XLTM/XLTX 等多种文档格式,高度兼容带有样式、图片(表)、透视表、切片器等复杂组件的文档,并提供流式读写 API,用于处理包含大规模数据的工作簿。可应用于各类报表平台、云计算、边缘计算等系统。
摘自Excelize官方文档
核心资源
- 源码仓库:https://github.com/xuri/excelize
- Issue:https://github.com/xuri/excelize/issues/
- go.dev:https://pkg.go.dev/github.com/xuri/excelize/v2
- 官方文档:https://xuri.me/excelize/zh-hans
1.1 安装与更新
各版本 Excelize 基础库所需要的最低 Go 语言版本兼容性如下:
表 1: Excelize 与 Go 语言版本兼容性对照表
| Excelize 版本 | 对 Go 语言版本的最低要求 |
|---|---|
| v2.9.1 ~ master | 1.23.0 |
| v2.8.1 ~ v2.9.0 | 1.18 |
| v2.7.0 ~ v2.8.0 | 1.16 |
| v2.4.0 ~ v2.6.1 | 1.15 |
| v2.0.2 ~ v2.3.2 | 1.10 |
| v1.0.0 ~ v2.0.1 | 1.6 |
如果使用 Go Modules 管理依赖,可以执行以下命令进行安装和更新:
# 安装最新版
go get github.com/xuri/excelize/v2
# 更新到最新稳定版
go get -u github.com/xuri/excelize/v2
# 更新到最新开发分支代码
go get -u github.com/xuri/excelize/v2@master1.2 读写Excel文档
1.2.1 创建Excel文档
以下示例展示了如何创建一个新的 Excel 工作簿、添加工作表并写入数据。
package main
import (
"fmt"
"github.com/xuri/excelize/v2"
)
func main() {
// 1. 创建一个新的工作簿
f := excelize.NewFile()
// 确保工作簿在关闭时释放资源
defer func() {
if err := f.Close(); err != nil {
fmt.Println(err)
}
}()
// 2. 创建一个名为“Sheet2”的新工作表
index, err := f.NewSheet("Sheet2")
if err != nil {
fmt.Println(err)
return
}
// 3. 定义要写入的数据
data := [][]interface{}{
{nil, "Apple", "Orange", "Pear"},
{"Small", 2, 3, 3},
{"Normal", 5, 2, 4},
{"Large", 6, 7, 8},
}
// 4. 遍历数据,写入单元格
for rowIdx, row := range data {
for colIdx, cellValue := range row {
// 将行列索引转换为单元格地址(如 (1,1) -> “A1“)
cellName, err := excelize.CoordinatesToCellName(colIdx+1, rowIdx+1)
if err != nil {
fmt.Printf("生成单元格名称失败:%v\n", err)
return
}
// 设置单元格的值
if err := f.SetCellValue("Sheet2", cellName, cellValue); err != nil {
fmt.Printf("设置单元格值失败:%v", err)
return
}
}
}
// 5. 将“Sheet2”设置为默认激活的工作表
f.SetActiveSheet(index)
// 6. 保存文件
if err := f.SaveAs("Book1.xlsx"); err != nil {
fmt.Println(err)
}
}执行上述代码后,将生成一个 Book1.xlsx 文件,其“Sheet2”工作表内容如图1所示。
1.2.2 读取Excel文档
以下示例展示了如何打开一个已存在的 Excel 文件并读取其中的数据。
package main
import (
"fmt"
"github.com/xuri/excelize/v2"
)
func main() {
// 1. 打开文件
f, err := excelize.OpenFile("Book1.xlsx")
if err != nil {
fmt.Println(err)
return
}
defer func() {
if err := f.Close(); err != nil {
fmt.Println(err)
}
}()
// 2. 检查目标工作表是否存在
sheetName := "Sheet2"
index, _ := f.GetSheetIndex(sheetName)
if index == -1 {
fmt.Printf("工作表%s不存在\n", sheetName)
return
}
// 3. 获取工作表中的所有行数据
rows, err := f.GetRows(sheetName)
if err != nil {
fmt.Printf("读取工作表数据失败:%v\n", err)
return
}
// 4. 遍历并打印数据
fmt.Println("读取到的数据:")
for _, row := range rows {
for _, col := range row {
fmt.Printf("%s\t", col)
}
fmt.Println()
}
}运行此程序,将输出之前创建的文件内容。
1.2.3 插入图表
Excelize 支持创建丰富的图表。以下示例先写入数据,然后基于数据创建一个三维簇状柱形图。
package main
import (
"fmt"
"github.com/xuri/excelize/v2"
)
func main() {
f := excelize.NewFile()
defer func() {
if err := f.Close(); err != nil {
fmt.Println(err)
}
}()
// 1. 向“Sheet1”写入数据
for idx, row := range [][]interface{}{
{nil, "Apple", "Orange", "Pear"},
{"Small", 2, 3, 3},
{"Normal", 5, 2, 4},
{"Large", 6, 7, 8},
} {
cell, err := excelize.CoordinatesToCellName(1, idx+1)
if err != nil {
fmt.Println(err)
return
}
f.SetSheetRow("Sheet1", cell, &row)
}
// 2. 在E1单元格位置添加一个三维簇状柱形图
if err := f.AddChart("Sheet1", "E1", &excelize.Chart{
Type: excelize.Col3DClustered,
Series: []excelize.ChartSeries{
{Name: "Sheet1!$A$2", Categories: "Sheet1!$B$1:$D$1", Values: "Sheet1!$B$2:$D$2"},
{Name: "Sheet1!$A$3", Categories: "Sheet1!$B$1:$D$1", Values: "Sheet1!$B$3:$D$3"},
{Name: "Sheet1!$A$4", Categories: "Sheet1!$B$1:$D$1", Values: "Sheet1!$B$4:$D$4"},
},
Title: []excelize.RichTextRun{{Text: "Fruit 3D Clustered Column Chart"}},
}); err != nil {
fmt.Println(err)
return
}
// 3. 保存文件
if err := f.SaveAs("Book1.xlsx"); err != nil {
fmt.Println(err)
}
}生成的 Excel 文件将包含一个图表,效果如图2所示。
1.2.4 插入图片
可以向工作表中插入本地或网络图片,并控制其显示属性。
package main
import (
"fmt"
_ "image/gif"
_ "image/jpeg"
_ "image/png"
"github.com/xuri/excelize/v2"
)
func main() {
f := excelize.NewFile()
defer func() {
if err := f.Close(); err != nil {
fmt.Println(err)
}
}()
// 1. 插入图片并缩放40%
if err := f.AddPicture("Sheet1", "E2", "./pics/Img.jpg",
&excelize.GraphicOptions{ScaleX: 0.4, ScaleY: 0.4}); err != nil {
fmt.Println(err)
return
}
// 2. 插入GIF图片,并设置更多属性(偏移、缩放、锁定等)
enable, disable := true, false
if err := f.AddPicture("Sheet1", "I2", "./pics/Java.gif",
&excelize.GraphicOptions{
PrintObject: &enable,
LockAspectRatio: false,
OffsetX: 15,
OffsetY: 10,
Locked: &disable,
ScaleX: 0.8,
ScaleY: 0.8,
}); err != nil {
fmt.Println(err)
return
}
if err := f.SaveAs("Book1.xlsx"); err != nil {
fmt.Println(err)
}
}插入图片后的效果如图3所示。
2. 工作簿、工作表与单元格操作
2.1 工作簿操作
工作簿(Workbook)是Excel文件本身。Excelize提供了创建、打开、保存、保护等核心API。
表 2: 操作 Excel 工作簿(Workbook)的核心 API
| API 函数 | 函数说明 |
|---|---|
func NewFile(options ...Options) *File | 用默认模板创建 Excel 文档,默认含 Sheet1 工作表。 |
func OpenFile(filename string, opts ...Options) (*File, error) | 打开指定路径的 Excel 文档。 |
func OpenReader(r io.Reader, opts ...Options) (*File, error) | 从数据流(如HTTP响应体)读取并打开 Excel 文档。 |
func (f *File) Save(options ...Options) error | 保存到创建或打开时的原始路径。 |
func (f *File) SaveAs(name string, opts ...Options) error | 另存 Excel 文档到新路径。 |
func (f *File) Close() error | 关闭文档,清理临时文件。 |
func (f *File) ProtectWorkbook(options *WorkbookProtectionOptions) error | 保护(如加密)工作簿。 |
func (f *File) UnprotectWorkbook(password ...string) error | 取消工作簿保护。 |
2.2 工作表操作
工作表(Sheet)是工作簿内的具体表格。Excelize 提供了完整的工作表管理功能。
表 3: 操作 Excel 工作表(Sheet)的核心 API
| API 函数 | 函数说明 |
|---|---|
func (f *File) NewSheet(sheet string) (int, error) | 新建工作表,返回索引。 |
func (f *File) DeleteSheet(sheet string) error | 删除工作表。 |
func (f *File) CopySheet(from, to int) error | 复制工作表。 |
func (f *File) SetSheetName(source, target string) error | 重命名工作表。 |
func (f *File) GetSheetList() (list []string) | 获取所有工作表名称列表。 |
func (f *File) GetSheetIndex(sheet string) (int, error) | 通过名称获取工作表索引。 |
func (f *File) SetSheetVisible(sheet string, visible bool) error | 设置工作表是否可见。 |
func (f *File) SetActiveSheet(index int) | 设置默认激活的工作表。 |
2.3 单元格基础
2.3.1 单元格引用与坐标处理
单元格地址主要有 A1 引用(如 B3)和 R1C1 引用(如 R3C2)两种形式。Excelize 默认使用 A1 引用,并提供了转换函数。
表 4: 单元格坐标处理 API
| API 函数 | 函数说明 |
|---|---|
func CoordinatesToCellName(col, row int, abs ...bool) (string, error) | 将行列编号 (1,1) 转换为 A1 地址 (“A1“)。 |
func CellNameToCoordinates(cell string) (int, int, error) | 将 A1 地址 (“B3“) 转换为行列编号 (2, 3)。 |
func ColumnNumberToName(num int) (string, error) | 将列编号 (1) 转换为列名 (“A“)。 |
func ColumnNameToNumber(name string) (int, error) | 将列名 (“C“) 转换为列编号 (3)。 |
2.3.2 单元格读写
表 5: 单元格赋值与读取 API
| API 函数 | 函数说明 |
|---|---|
func (f *File) SetCellValue(sheet, cell string, value interface{}) error | 通用设置单元格值(支持多种类型)。 |
func (f *File) SetCellStr/Int/Float/Bool(...) | 设置特定类型的单元格值。 |
func (f *File) GetCellValue(sheet, cell string, opts ...Options) (string, error) | 获取单元格格式化后的字符串值。 |
func (f *File) GetCellType(sheet, cell string) (CellType, error) | 获取单元格的数据类型。 |
内联存储值:指直接在单元格的 XML 节点中存储数据值(如 <v>42</v>),而非通过共享字符串表引用。这种方式对数值、日期等非文本数据效率更高。
2.3.3 单元格合并与公式
表 6: 单元格合并与公式 API
| API 函数 | 函数说明 |
|---|---|
func (f *File) MergeCell(sheet, topLeftCell, bottomRightCell string) error | 合并单元格区域。 |
func (f *File) UnmergeCell(sheet, topLeftCell, bottomRightCell string) error | 取消合并单元格区域。 |
func (f *File) SetCellFormula(sheet, cell, formula string, opts ...FormulaOptions) error | 设置单元格公式(如 =SUM(A1:B2))。 |
func (f *File) CalcCellValue(sheet, cell string, opts ...Options) (result string, err error) | 计算公式单元格的结果。 |
2.4 行列处理
2.4.1 行列插入、删除与调整
表 7: 行列处理 API
| API 函数 | 函数说明 |
|---|---|
func (f *File) InsertRows(sheet string, row, n int) error | 在指定行前插入 n 行。 |
func (f *File) RemoveRow(sheet string, row int) error | 删除指定行。 |
func (f *File) InsertCols(sheet, col string, n int) error | 在指定列前插入 n 列。 |
func (f *File) RemoveCol(sheet, col string) error | 删除指定列。 |
func (f *File) SetRowHeight(sheet string, row int, height float64) error | 设置行高。 |
func (f *File) SetColWidth(sheet, startCol, endCol string, width float64) error | 设置单列或多列宽度。 |
func (f *File) SetRowVisible(sheet string, row int, visible bool) error | 设置行可见性。 |
func (f *File) SetColVisible(sheet, columns string, visible bool) error | 设置列可见性。 |
3. 样式与条件格式
3.1 创建与设置样式
样式是一组格式特征的集合,如边框、填充、字体、对齐等。通过 NewStyle 函数创建样式并获取索引,然后使用 SetCellStyle 等函数应用。
表 8: 创建与应用样式 API
| API 函数 | 函数说明 |
|---|---|
func (f *File) NewStyle(style *Style) (int, error) | 创建新样式,返回样式ID。 |
func (f *File) SetCellStyle(sheet, topLeftCell, bottomRightCell string, styleID int) error | 为单元格区域应用样式。 |
func (f *File) SetRowStyle(sheet string, start, end, styleID int) error | 为行应用样式。 |
func (f *File) SetColStyle(sheet, columns string, styleID int) error | 为列应用样式。 |
Style 结构体定义了所有格式选项:
表 9: *Style 支持的格式选项
| 选项 | 描述 |
|---|---|
Border []Border | 边框样式(类型、颜色、线型)。 |
Fill Fill | 填充格式(颜色、图案、渐变)。 |
Font *Font | 字体格式(名称、大小、颜色、加粗等)。 |
Alignment *Alignment | 对齐方式(水平、垂直、自动换行等)。 |
NumFmt int | 数字格式索引。 |
CustomNumFmt string | 自定义数字格式。 |
边框 (Border) 选项示例:
style, err := f.NewStyle(&excelize.Style{
Border: []excelize.Border{
{Type: "left", Color: "000000", Style: 1}, // 左边框,黑色细实线
{Type: "top", Color: "FF0000", Style: 2}, // 上边框,红色粗实线
},
})填充 (Fill) 选项示例:
style, err := f.NewStyle(&excelize.Style{
Fill: excelize.Fill{
Type: "pattern", Pattern: 1, Color: []string{"FFFF00"}, // 实心黄色填充
},
})字体 (Font) 与对齐 (Alignment) 选项示例:
style, err := f.NewStyle(&excelize.Style{
Font: &excelize.Font{Bold: true, Size: 14, Color: "1a5fb4"},
Alignment: &excelize.Alignment{Horizontal: "center", Vertical: "center", WrapText: true},
})3.2 条件格式
条件格式允许根据单元格的值动态应用样式。
表 10: 条件格式 API
| API 函数 | 函数说明 |
|---|---|
func (f *File) NewConditionalStyle(style *Style) (int, error) | 创建用于条件格式的样式。 |
func (f *File) SetConditionalFormat(sheet, rangeRef string, opts []ConditionalFormatOptions) error | 为单元格区域设置条件格式规则。 |
ConditionalFormatOptions 定义了规则,其核心字段是 Type(规则类型)和对应的条件参数。例如,高亮大于100的单元格:
// 1. 创建条件格式样式(红色填充)
redStyle, _ := f.NewConditionalStyle(&excelize.Style{Fill: excelize.Fill{Type: "pattern", Color: []string{"FFCCCC"}, Pattern: 1}})
// 2. 定义规则
err := f.SetConditionalFormat("Sheet1", "A1:A10",
[]excelize.ConditionalFormatOptions{
{
Type: "cell",
Criteria: ">",
Value: "100",
Format: &redStyle, // 应用红色样式
},
})4. 图表、迷你图与图片
4.1 图表
图表是数据可视化的重要工具。Excelize 支持创建多达55种类型的图表。
表 11: 图表核心 API
| API 函数 | 函数说明 |
|---|---|
func (f *File) AddChart(sheet, cell string, chart *Chart, combo ...*Chart) error | 在工作表中添加图表。 |
func (f *File) AddChartSheet(sheet string, chart *Chart, combo ...*Chart) error | 创建单独的图表工作表。 |
Chart 结构体是图表的配置核心,主要包含 Type(图表类型,如 excelize.Col3DClustered)、Series(数据系列)和 Title(标题)等字段。ChartSeries 用于定义每个数据系列的数据来源(Values)、分类(Categories)和名称(Name)。
4.2 迷你图
迷你图(Sparkline)是嵌入在单元格中的微型图表,用于显示数据趋势。
表 12: 迷你图 API 与配置
| API 函数/配置项 | 描述 |
|---|---|
func (f *File) AddSparkline(sheet string, opts *SparklineOptions) error | 添加迷你图。 |
SparklineOptions.Location | 必填,迷你图放置的单元格范围。 |
SparklineOptions.Range | 必填,迷你图的数据来源范围。 |
SparklineOptions.Type | 类型:line(折线)、column(柱形)、win_loss(盈亏)。 |
err := f.AddSparkline("Sheet1", &excelize.SparklineOptions{
Location: []string{"F2:F4"},
Range: []string{"B2:D4"},
Type: "column",
})4.3 图片
除了基础的 AddPicture,还可以从字节流添加图片。
表 13: 图片操作 API
| API 函数 | 函数说明 |
|---|---|
func (f *File) AddPictureFromBytes(sheet, cell string, pic *Picture) error | 从字节数组添加图片。 |
func (f *File) GetPictureCells(sheet string) ([]string, error) | 获取包含图片的单元格列表。 |
Picture 结构体需指定文件扩展名(Extension)和文件字节数据(File)。
5. 数据验证与筛选
5.1 数据验证
数据验证用于限制用户在单元格中的输入,例如创建下拉列表、限制数字范围等。
表 14: 数据验证 API 使用流程
| API 函数 | 函数说明 |
|---|---|
dv := NewDataValidation(true) | 创建一个数据验证对象。 |
dv.SetSqref(“A1:A10”) | 设置验证规则应用的单元格范围。 |
dv.SetRange(...) | 设置验证条件(类型、运算符、值)。 |
f.AddDataValidation(“Sheet1”, dv) | 将验证规则添加到工作表。 |
示例:在 A1 单元格创建“是/否”下拉列表。
dv := excelize.NewDataValidation(true)
dv.SetSqref(“A1”) // 应用范围
// 设置验证类型为列表,列表选项为“是,否”
if err := dv.SetDropList([]string{“是”, “否”}); err != nil {
fmt.Println(err)
}
dv.SetInput(“提示”, “请从下拉列表中选择“) // 设置输入提示
if err := f.AddDataValidation(“Sheet1”, dv); err != nil {
fmt.Println(err)
}5.2 自动筛选与表格
自动筛选可以为数据表添加筛选按钮,而表格(Table)是一种带有样式和筛选功能的结构化区域。
表 15: 筛选与表格 API
| API 函数 | 函数说明 |
|---|---|
func (f *File) AutoFilter(sheet, rangeRef string, opts []AutoFilterOptions) error | 为区域添加自动筛选。 |
func (f *File) AddTable(sheet string, table *Table) error | 将区域转换为表格。 |
// 为区域 A1:D10 添加自动筛选
err := f.AutoFilter(“Sheet1”, “A1:D10”, []excelize.AutoFilterOptions{})
// 将区域 A1:D9 转换为名为“MyTable”的表格
err := f.AddTable(“Sheet1”, &excelize.Table{Range: “A1:D9”, Name: “MyTable”})【本篇核心知识点速记】
- 快速上手:使用
excelize.NewFile()创建,f.SaveAs()保存;使用excelize.OpenFile()打开。SetCellValue和GetRows是读写数据的核心。 - 核心对象管理:
- 工作簿:对应
File结构体,是操作的入口。 - 工作表:使用
NewSheet、DeleteSheet、GetSheetList管理。 - 单元格:使用
CoordinatesToCellName处理坐标,SetCellValue/Formula和GetCellValue进行读写,MergeCell进行合并。 - 行列:使用
InsertRows/Cols、RemoveRow/Col、SetRowHeight/ColWidth进行结构调整。
- 工作簿:对应
- 样式系统:
- 通过
NewStyle(&excelize.Style{...})创建样式,获得样式ID。 - 在
Style中定义Border、Fill、Font、Alignment等所有格式。 - 使用
SetCellStyle将样式ID应用到单元格区域。 - 条件格式:用
NewConditionalStyle创建样式,用SetConditionalFormat设置规则,实现动态格式。
- 通过
- 可视化与嵌入:
- 图表:用
AddChart添加,核心是配置Chart结构体,特别是Type和Series(数据系列)。 - 迷你图:用
AddSparkline添加微型趋势图。 - 图片:用
AddPicture添加本地图片,或用AddPictureFromBytes添加字节流图片。
- 图表:用
- 数据质量与控制:
- 数据验证:通过
NewDataValidation->SetSqref->SetRange/SetDropList->AddDataValidation流程,为单元格设置输入限制。 - 筛选与表格:
AutoFilter为区域添加筛选按钮;AddTable创建具有固定样式的表格区域。
- 数据验证:通过
