go操作excel
今天出一个专题教程 如何使用go语言操作excel 背景是 我需要对表格中的数据先做一个筛选,然后按照聚合统计,重点分析其中的几个数据 接入我们自己的一些系统然后继续分析 然后发现这样的操作
go操作excel
发布时间:2025-01-26 (2025-01-26)

今天出一个专题教程

如何使用go语言操作excel

背景是

我需要对表格中的数据先做一个筛选,然后按照聚合统计,重点分析其中的几个数据

接入我们自己的一些系统然后继续分析

然后发现这样的操作,具有相当高的重复性,我就在想能不能

写一个通用的脚本来实现这个操作

go读取excel

使用的库是github.com/tealeg/xlsx

xlsx文件读取

xlsx本质上是压缩包,这个大家应该都知道吧

可以把xlsx文件改个名,比如xxx.zip,然后解压,你就能得到这些东西

实际上这些工具就是去解析其中的xml文件,然后拿到对应数据的

  1. 通过文件名读取
func read1() {
  file, err := xlsx.OpenFile("0126可疑ip.xlsx")
  if err != nil {
    fmt.Println("Error opening file:", err)
    return
  }
  fmt.Println(file.Sheet)
}
  1. 通过字节数组读取
func read2() {
  byteData, err := os.ReadFile("0126可疑ip.xlsx")
  if err != nil {
    fmt.Println("读取文件失败", err)
    return
  }
  file, err := xlsx.OpenBinary(byteData)
  if err != nil {
    fmt.Println("Error opening file:", err)
    return
  }
  fmt.Println(file.Sheet)
}
  1. 通过readerAt接口读取

一般用于封装

func read3() {
  file, err := os.Open("0126可疑ip.xlsx")
  if err != nil {
    fmt.Println("打开文件失败", err)
    return
  }
  info, _ := file.Stat()
  xFile, err := xlsx.OpenReaderAt(file, info.Size())
  if err != nil {
    fmt.Println("Error opening file:", err)
    return
  }
  fmt.Println(xFile.Sheet)
}

补充:为什么xlsx需要io.ReaderAt接口,而不是io.Reader接口

特性 io.Reader io.ReaderAt
读取方式 顺序读取 随机访问(可以从任意位置读取)
数据源状态 读取后数据会从流中移除(破坏性读取) 读取后数据源不变(非破坏性读取)
适用场景 流式数据(如网络流、文件流) 大文件、需要随机访问的场景
性能 适合小文件或流式处理 适合大文件或需要分块读取的场景
是否支持回溯 不支持(除非结合Seek 支持(可以随时读取任意位置)

数据读取

  1. 先确定哪一个sheet
  2. 然后读行
  3. 然后遍历每一列
func readData() {
  file, err := xlsx.OpenFile("0126可疑ip.xlsx")
  if err != nil {
    fmt.Println("Error opening file:", err)
    return
  }
  sheet := file.Sheets[0]
  for _, row := range sheet.Rows {
    for _, cell := range row.Cells {
      fmt.Printf("%v \t", cell.Value)
    }
    fmt.Println()
  }
}

数据读取实战练习

读取0126可疑ip.xlsx,将其中的top10攻击ip拿出来,显示出攻击ip和攻击次数

func readData1() {
  file, err := xlsx.OpenFile("0126可疑ip.xlsx")
  if err != nil {
    fmt.Println("Error opening file:", err)
    return
  }
  sheet := file.Sheets[0]

  // 获取去重之后的ip
  var uniqueIPMap = map[string]int{}
  for _, row := range sheet.Rows[1:] {
    ip := row.Cells[1].String()
    _, ok := uniqueIPMap[ip]
    if ok {
      uniqueIPMap[ip]++
    } else {
      uniqueIPMap[ip] = 1
    }
  }

  type IPData struct {
    IP    string
    Count int
  }
  var uniqueIPList []IPData
  for s, i := range uniqueIPMap {
    uniqueIPList = append(uniqueIPList, IPData{
      IP:    s,
      Count: i,
    })
  }

  sort.Slice(uniqueIPList, func(i, j int) bool {
    return uniqueIPList[i].Count > uniqueIPList[j].Count
  })
  for _, info := range uniqueIPList[:10] {
    fmt.Println(info.IP, info.Count)
  }

}

go写入excel

  1. 创建sheet
  2. 创建row
  3. 创建column
func write() {
  file := xlsx.NewFile()
  sheet, _ := file.AddSheet("sheet1")
  var headers = []string{
    "时间",
    "攻击IP",
    "攻击次数",
  }
  headerRow := sheet.AddRow()
  for _, header := range headers {
    headerRow.AddCell().Value = header
  }
  font := xlsx.NewFont(12, "Calibra")
  style := xlsx.NewStyle()
  style.Font = *font
  for i := 0; i < 10; i++ {
    row := sheet.AddRow()
    row.AddCell().Value = time.Now().Format("2006-01-02")
    cell := row.AddCell()
    cell.SetString(fmt.Sprintf("192.168.100.%d", i+1))
    cell.SetStyle(style)
    row.AddCell().SetInt(i + 1)
  }
  err := file.Save("xxx.xlsx")
  fmt.Println(err)
}