如何使用 Go 和 Excelize 构建电子表格

前言

分析任何规模的数据的重要性怎么强调都不为过。 我们日常生活的几乎每个部分都是数据驱动的,作为开发人员,在构建任何合理大小的应用程序时,首要考虑的因素之一是使用什么数据库以及如何构建数据。

但是,它不仅限于存储数据,您还需要通过提取并以任何非技术人员都能理解的格式呈现这些数据来理解这些数据。 例如,电子商务企业每天都会产生大量数据,这意味着我们需要跟踪产品库存、月收入、财务报表等信息。 目前,有许多服务提供这些类型的解决方案,但快速提取和呈现数据的最简单方法之一是生成电子表格或 CSV 文件。

在本文中,我们将探索如何在 Go 中创建电子表格,方法是构建一个简单的费用报告并使用 Excelize 库将其导出为 CSV 格式。 中找到本教程的完整代码 您可以在 GitHub 存储库 。 让我们开始吧!

  • 生成费用报告
  • 创建工作表
  • 添加数据和创建样式
  • 保存工作表
  • 导出为 CSV

生成费用报告

费用报告是一份详细的清单,尽可能详细地显示公司在一段时间内的支出。 我们将构建一个类似于下图中的报告:

创建工作表

要开始使用,请确保您已安装 Go ≥v1.15 并创建一个新的项目文件夹。

在项目目录中,创建一个 main.go文件并使用以下代码初始化 Go 模块:

$ mkdir 
$ cd 
$ touch main.go
$ go mod init github.com//

The main.go file is the entry point of our Go application, and we use the generated go.mod file for dependency management. Next, install the Excelize library by running the command below:

$ go get github.com/xuri/excelize/v2

Excelize is a Go library with no dependencies that provides primitives for reading and writing to XLSX files and other supported spreadsheet file formats. In your main.go file, import Excelize, create a new file, create a new worksheet, and set the active sheet to the worksheet you just created:

package main
import "github.com/xuri/excelize/v2"
const (
   SheetName = "Expense Report"
)
func main() {
   var err error
   f := excelize.NewFile()
   index := f.NewSheet("Sheet1")
   f.SetActiveSheet(index)
   f.SetSheetName("Sheet1", SheetName)
}

添加数据和创建样式

创建工作表后,我们可以开始构建报告。 首先,我们将设置一些尺寸以适应我们想要的结构,如下图所示。

将以下代码块添加到您的 main功能:

//main.go
//...
   err = f.SetColWidth(SheetName, "A", "A", 6)
   err = f.SetColWidth(SheetName, "H", "H", 6)
   err = f.SetColWidth(SheetName, "B", "B", 12)
   err = f.SetColWidth(SheetName, "C", "C", 16)
   err = f.SetColWidth(SheetName, "D", "D", 13)
   err = f.SetColWidth(SheetName, "E", "E", 15)
   err = f.SetColWidth(SheetName, "F", "F", 22)
   err = f.SetColWidth(SheetName, "G", "G", 13)

我们只需要列 A至 G对于报告,所以我们使用 SetColWidth调整列的宽度以满足我们的要求。 你会注意到我们已经定义了一个 error变量到顶部 main函数,我们只是将这些函数返回的任何错误分配给它。 理想情况下,您应该正确处理每个错误,因为它在 Go 中是惯用的,但保持代码最少也是可以的。

Over 200k developers use LogRocket to create better digital experiences Learn more →

报告的第一部分包含静态信息,因此我们将对其进行硬编码。 将以下代码块添加到您的 main 函数中:

//main.go
//...
   err = f.SetRowHeight(SheetName, 1, 12)
   err = f.MergeCell(SheetName, "A1", "H1")
​
   err = f.SetRowHeight(SheetName, 2, 25)
   err = f.MergeCell(SheetName, "B2", "D2")
​
   style, err := f.NewStyle(&excelize.Style{Font: &excelize.Font{Size: 20, Color: "6d64e8"}})
   err = f.SetCellStyle(SheetName, "B2", "D2", style)
   err = f.SetSheetRow(SheetName, "B2", &[]interface{}{"Gigashots Inc."})
   err = f.MergeCell(SheetName, "B3", "D3")
   err = f.SetSheetRow(SheetName, "B3", &[]interface{}{"3154 N Richardt Ave"})
​
   err = f.MergeCell(SheetName, "B4", "D4")
   err = f.SetSheetRow(SheetName, "B4", &[]interface{}{"Indianapolis, IN 46276"})
​
   style, err = f.NewStyle(&excelize.Style{Font: &excelize.Font{Color: "666666"}})
   err = f.MergeCell(SheetName, "B5", "D5")
   err = f.SetCellStyle(SheetName, "B5", "D5", style)
   err = f.SetSheetRow(SheetName, "B5", &[]interface{}{"(317) 854-0398"})
​
   style, err = f.NewStyle(&excelize.Style{Font: &excelize.Font{Size: 32, Color: "2B4492", Bold: true}})
   err = f.MergeCell(SheetName, "B7", "G7")
   err = f.SetCellStyle(SheetName, "B7", "G7", style)
   err = f.SetSheetRow(SheetName, "B7", &[]interface{}{"Expense Report"})
​
   style, err = f.NewStyle(&excelize.Style{Font: &excelize.Font{Size: 13, Color: "E25184", Bold: true}})
   err = f.MergeCell(SheetName, "B8", "C8")
   err = f.SetCellStyle(SheetName, "B8", "C8", style)
   err = f.SetSheetRow(SheetName, "B8", &[]interface{}{"09/04/00 - 09/05/00"})
​
   style, err = f.NewStyle(&excelize.Style{Font: &excelize.Font{Size: 13, Bold: true}})
   err = f.SetCellStyle(SheetName, "B10", "G10", style)
   err = f.SetSheetRow(SheetName, "B10", &[]interface{}{"Name", "", "Employee ID", "", "Department"})
   err = f.MergeCell(SheetName, "B10", "C10")
   err = f.MergeCell(SheetName, "D10", "E10")
   err = f.MergeCell(SheetName, "F10", "G10")
​
   style, err = f.NewStyle(&excelize.Style{Font: &excelize.Font{Color: "666666"}})
   err = f.SetCellStyle(SheetName, "B11", "G11", style)
   err = f.SetSheetRow(SheetName, "B11", &[]interface{}{"John Doe", "", "#1B800XR", "", "Brand & Marketing"})
   err = f.MergeCell(SheetName, "B11", "C11")
   err = f.MergeCell(SheetName, "D11", "E11")
   err = f.MergeCell(SheetName, "F11", "G11")
​
   style, err = f.NewStyle(&excelize.Style{Font: &excelize.Font{Size: 13, Bold: true}})
   err = f.SetCellStyle(SheetName, "B13", "G13", style)
   err = f.SetSheetRow(SheetName, "B13", &[]interface{}{"Manager", "", "Purpose"})
   err = f.MergeCell(SheetName, "B13", "C13")
   err = f.MergeCell(SheetName, "D13", "E13")
​
   style, err = f.NewStyle(&excelize.Style{Font: &excelize.Font{Color: "666666"}})
   err = f.SetCellStyle(SheetName, "B14", "G14", style)
   err = f.SetSheetRow(SheetName, "B14", &[]interface{}{"Jane Doe", "", "Brand Campaign"})
   err = f.MergeCell(SheetName, "B14", "C14")
   err = f.MergeCell(SheetName, "D14", "E14")

这段代码中有很多内容,所以让我们分解一下。

如前所述,Excelize 提供了一组原始函数来操作电子表格。 您需要的每个功能只需要在文件对象上调用一个方法,该方法接受一些参数。

在这种情况下,我们使用了五种主要方法:

  • SetRowHeight
  • MergeCell
  • NewStyle
  • SetCellStyle
  • SetSheetRow

SetRowHeight调整给定行的高度,以及 MergeCell将一行中的多个单元格合并为一个单元格。 要编写样式,我们可以使用 excelize.Stylestruct,它提供了定义自定义样式所需的属性。 这 NewStyle方法只是采用 Style对象并返回表示样式的索引。

定义您的自定义样式后,我们可以使用 SetCellStyle将样式应用于单个单元格或一系列单元格。 我们用 SetSheetRow将数据添加到单行中的一个单元格或一系列单元格。 它接受一个接口切片,它是任何原始数据类型的容器。 切片是位置的,每个元素将从提供的轴开始放置在相应的单元格中。 因此,在合并多个单元格的某些情况下,我们使用了空字符串。

报告的第二部分是一个包含任意长度的动态数据的表格,这意味着我们不能像以前那样只定义每一行的内容。 表中表示的数据遵循定义的结构,因此我们可以循环传入数据并动态创建每一行。

让我们定义一些代表费用列表的任意数据。

在您的顶部 main.go文件,在 main函数,添加以下变量:

//main.go
//...
var (
   expenseData = [][]interface{}{
      {"2022-04-10", "Flight", "Trip to San Fransisco", "", "", "$3,462.00"},
      {"2022-04-10", "Hotel", "Trip to San Fransisco", "", "", "$1,280.00"},
      {"2022-04-12", "Swags", "App launch", "", "", "$862.00"},
      {"2022-03-15", "Marketing", "App launch", "", "", "$7,520.00"},
      {"2022-04-11", "Event hall", "App launch", "", "", "$2,080.00"},
   }
)
//...

现在,将以下代码块添加到您的 main 函数中:

//main.go
//...
   style, err = f.NewStyle(&excelize.Style{
      Font:      &excelize.Font{Size: 13, Bold: true, Color: "2B4492"},
      Alignment: &excelize.Alignment{Vertical: "center"},
   })
   err = f.SetCellStyle(SheetName, "B17", "G17", style)
   err = f.SetSheetRow(SheetName, "B17", &[]interface{}{"Date", "Category", "Description", "", "Notes", "Amount"})
   err = f.MergeCell(SheetName, "D17", "E17")
   err = f.SetRowHeight(SheetName, 17, 32)
​
   startRow := 18
   for i := startRow; i < (len(expenseData) + startRow); i++ {
      var fill string
      if i%2 == 0 {
         fill = "F3F3F3"
      } else {
         fill = "FFFFFF"
      }
      style, err = f.NewStyle(&excelize.Style{
         Fill:      excelize.Fill{Type: "pattern", Pattern: 1, Color: []string{fill}},
         Font:      &excelize.Font{Color: "666666"},
         Alignment: &excelize.Alignment{Vertical: "center"},
      })
      err = f.SetCellStyle(SheetName, fmt.Sprintf("B%d", i), fmt.Sprintf("G%d", i), style)
      err = f.SetSheetRow(SheetName, fmt.Sprintf("B%d", i), &expenseData[i-18])
      err = f.SetCellRichText(SheetName, fmt.Sprintf("C%d", i), []excelize.RichTextRun{
         {Text: expenseData\[i-18\][1].(string), Font: &excelize.Font{Bold: true}},
      })
​
      err = f.MergeCell(SheetName, fmt.Sprintf("D%d", i), fmt.Sprintf("E%d", i))
      err = f.SetRowHeight(SheetName, i, 18)
   }

我们仍然使用相同的方法来组合样式和添加数据。 但是,我们正在循环 expenseData列出并将每个项目添加到当前行。 我们开始循环 18,这是电子表格中的当前行。 为了使表格的行更加清晰易读,我们通过使用 modulo手术。

导出为 CSV

到目前为止,我们已经探索了使用 XLSX 文件,但是,还有其他格式适合呈现这种数据。 CSV 文件是一个文本文件,其中包含由逗号分隔的数据行,主要用于导入和导出数据。

考虑一种情况,我们希望将费用报告中的表存储在某个自托管数据库中。 我们可以将这个表格提取为 CSV 格式,然后通过几个步骤将其导入数据库。

首先,在主函数之外创建一个名为 generateCSV并在下面添加代码块:

//main.go
//...
type Axis struct {
   row int
   col string
}
​
func generateCSV(f *excelize.File, start, end Axis) error {
   var data [][]string
​
   for i := start.row; i <= end.row; i++ {
      row := []string{}
      for j := []rune(start.col)[0]; j <= []rune(end.col)[0]; j++ {
         value, err := f.GetCellValue(SheetName, fmt.Sprintf("%s%d", string(j), i), excelize.Options{})
         if err != nil {
            return err
         }
         row = append(row, value)
      }
      data = append(data, row)
   }
​
   file, err := os.Create("expenses.csv")
   if err != nil {
      return err
   }
   defer f.Close()
​
   writer := csv.NewWriter(file)
   return writer.WriteAll(data)
}

这 generateCSV函数接受一个 excelize.File类型、起始轴和结束轴。 轴只是构成单元格的行和列的组合。 我们循环遍历每一行,对于每一行,我们循环遍历开始轴和结束轴边界内的每一列。

然后我们使用 f.GetCellValue提取每个单元格的当前值。 因为列表示为字母字符串,所以我们将它们转换为符文以获取底层的 unicode 十进制。 最后,我们将提取的数据保存到 .csv文件 使用标准库中的 CSV 包 。

我们可以在保存工作表并传递文件句柄后调用此函数。

在你的 main函数,添加以下代码块:

//main.go
///...
   err = f.SaveAs("expense-report.xlsx")
   err = generateCSV(f, Axis{17, "B"}, Axis{22, "G"})
​
   if err != nil {
      log.Fatal(err)
   }

我们提供了我们之前为工作表创建的文件和表示表格范围的轴。

如果你运行 main.go文件,您应该会看到生成的 XLSX 文件和 CSV 文件:

$ go run main.go

结论

以电子表格兼容的格式呈现数据有很多用例,包括分析、转换和验证。 在本文中,我们学习了如何使用 Go 和 Excelize 包通过生成费用报告来处理电子表格。

当您考虑 Excelize 开箱即用的其他功能时,我们只是触及了皮毛。 您可以添加图像、创建图表、迷你图、形状、数据透视表等。 我希望你学到了一些新的东西,如果你有任何问题,请发表评论。 快乐编码!

LogRocket 主动显示和诊断您的应用程序和网站中最重要的问题

成千上万的工程和产品团队使用 LogRocket 来减少了解技术和可用性问题的根本原因所需的时间。 使用 LogRocket,您将减少与客户来回对话的时间,并消除无休止的故障排除过程。 LogRocket 让您可以花更多时间构建新事物,而减少修复错误的时间。

到此这篇关于如何使用 Go 和 Excelize 构建电子表格的文章就介绍到这了,更多相关Go 与 Excelize 构建表格内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

你可能感兴趣的:(如何使用 Go 和 Excelize 构建电子表格)