【Go】Go 操作 excel 代码封装

github地址:https://github.com/zxmfke/train/tree/main/excel

平时写后端管理平台的时候,必不可少地写表格的导出导入功能,因此封装一下。github.com/xuri/excelize/v2这个包其实就可以封装excel,不过每次写入的时候都需要要指定位置,就是要指定写excel表格A列还是B列。这个包的主要目的也就是写入的时候,不需要每次都指定X轴和Y轴,除非是针对要写入特定位置的。

在这里插入图片描述

注意:这个代码的封装主要目的就是能够导出一个excel和读一个excel,不包含颜色呀,样式什么的。

Excel操作逻辑
  • 写入excel的时候,需要指定X轴和Y轴,X轴是大写英文字母,Y轴是以1开始递增的数字。X轴26个英文字母用完后,以AAAB的格式扩张;
  • 每次写入的是一个sheet,不能一次写入多个sheet,可以切换sheet来写入数据;
  • 读取excel的时候,返回是一个切片,每个切片的元素的类型是map,key为标题的值,value就是对应的数据。
Example
func main() {
   // 初始化 excel operator
	operator := excel.New([]excel.SheetConf{
		{Name: "测试中文Tab", ColLen: 20},
	})
	defer operator.Close()

	// 写入header
	headers := []string{}

	for i := 0; i < 20; i++ {
		headers = append(headers, fmt.Sprintf("%d", i))
	}

	if err := operator.WriteHeader(headers); err != nil {
		fmt.Println(fmt.Errorf("write header err : %s", err.Error()))
		return
	}

	// 写入数据
	data := make([][]string, 5)

	for i := 0; i < 5; i++ {
		data[i] = make([]string, 20)
		for j := 0; j < 20; j++ {
			data[i][j] = fmt.Sprintf("%d%d", i, j)
		}
	}

	if err := operator.WriteAll(data); err != nil {
		fmt.Println(fmt.Errorf("write data err : %s", err.Error()))
		return
	}

    // 保存 excel
	_ = operator.SaveAs("testdata/new.xlsx")
}
Export方法说明
初始化一个operator – New
type SheetConf struct {
	Name   string `json:"name"`
	ColLen int    `json:"colLen"`
}

// New 初始化返回一个Excel操作类,默认使用Sheet1作为首页和当前操作的sheet
func New(sheets []SheetConf) *Operator {

	if len(sheets) == 0 {
		sheets = defaultSheets
	}

	var (
		defaultSheet = sheets[0]
		operator     = &Operator{
			curSheet:  defaultSheet.Name,
			excelFile: excelize.NewFile(),
			sheetMap:  make(map[string]*sheet),
		}
	)

	defer func() {
		// excelize.NewFile会默认创建一个Sheet1的sheet
		if len(sheets) != 0 {
			operator.excelFile.DeleteSheet("Sheet1")
		}
	}()

	for i := 0; i < len(sheets); i++ {
		sheetIndex := operator.newSheet(sheets[i].Name)
		operator.sheetMap[sheets[i].Name] = &sheet{
			index:           sheetIndex,
			name:            sheets[i].Name,
			colMaxLen:       sheets[i].ColLen,
			rowCellTemplate: nil,
		}
	}

	operator.SwitchSheet(defaultSheet.Name)

	return operator
}

函数New用来初始化一个excel的operator,对excel的写入都是通过operator提供的方法。

SheetConf类型,里面的Name就是excel表格每个sheet的名称,ColLen是这个sheet的顶部header的数量

在这里插入图片描述

如果传入的是一个空的SheetsConf,会初始化一个Sheet1的sheet,不会报错

初始化之后,默认切到第一个sheet,作为要接下去要写入的sheet

切换sheet – SwitchSheet
// SwitchSheet 切换excel的tab
func (o *Operator) SwitchSheet(sheetName string) {

	var (
		sheetTab = o.sheetMap[sheetName]
	)

	sheetTab.initHeader()
	o.excelFile.SetActiveSheet(sheetTab.index)
	o.curSheet = sheetName
}

SwitchSheet会去初始化Sheet的header定位,每个sheet都有自己的rowCellTemplate,即每次要write的时候的定位模板。原本需要write excel时指定X和Y,在接下去的write的方法就只需要传入写入的值即可。

type sheet struct {
	index           int
	name            string
	colMaxLen       int
	rowCellTemplate []*cell
}

type cell struct {
	Col   string // 横轴字母表
	Row   int    // 第几行
	Value string
}

比如colMaxLen是5,那rowCellTemplate切片也会初始化5个值:

[{Col: "A"},{Col: "B"},{Col: "C"},{Col: "D"},{Col: "E"}]
写入excel – Write
WriteHeader

此函数默认写入第一行,当做header来写入,默认写入数据前,都要先写入一下header

// WriteHeader 写入header
func (o *Operator) WriteHeader(headers []string) error {

	...

	for i := 0; i < len(headers); i++ {
		curSheet.rowCellTemplate[i].Row = 1
		curSheet.rowCellTemplate[i].Value = headers[i]
	}

	return o.WriteRow(curSheet.rowCellTemplate...)
}
WriteAll

WriteAll是写入所有数据,excel表格可以理解为二维数组,X轴就是A、B、C这种的,Y轴是数字递增。传入的数据也必须是二维数组的。

// WriteAll 写入所有的数据,不包括header
func (o *Operator) WriteAll(cells [][]string) error {
    
   var rowBias = 2
   ...

   for i := 0; i < rows; i++ {
       
      ...

      for j := 0; j < cols; j++ {
         curSheet.rowCellTemplate[j].Row = i + rowBias
         curSheet.rowCellTemplate[j].Value = cells[i][j]
      }

      if err := o.WriteRow(curSheet.rowCellTemplate...); err != nil {
         return err
      }
   }

   return nil
}
WriteRow

WriteRow是写入每行数据,WriteHeaderWriteAll也是调用此方法去写入。调用excelFile.SetCellValuelocation,就是cell类型的方法,把X轴和Y轴拼接起来。

// WriteRow 写入单行数据
func (o *Operator) WriteRow(cells ...*cell) error {
   curSheet := o.getCurSheet()

   if len(cells) > curSheet.colMaxLen {
      return OutOfColumn
   }

   for _, c := range cells {
      if err := o.excelFile.SetCellValue(o.curSheet, c.location(), c.Value); err != nil {
         return err
      }
   }
   return nil
}
保存excel – SaveAs

调用write相关方法后,还不能算保存到excel里面,需要调用SaveAs的方法来落盘。传入的路径,如果文件夹没有创建的,会自动创建文件夹。

读取excel - Read

读取excel表格,就是用Read方法,返回的是[]map[string]string类型的结果。每个切片的值代表着一行,map的key就是header的值,value就是数据。


单元测试

主要函数的单元测试均已覆盖,可以看包内_test后缀的文件

通过go test -v -coverprofile=cover.out指令可以执行单元测试,单元测试覆盖率在 91.9%。


读取excel - Read

读取excel表格,就是用Read方法,返回的是[]map[string]string类型的结果。每个切片的值代表着一行,map的key就是header的值,value就是数据。


单元测试

主要函数的单元测试均已覆盖,可以看包内_test后缀的文件

通过go test -v -coverprofile=cover.out指令可以执行单元测试,单元测试覆盖率在 91.9%。


欢迎指教~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值