golang 生成excel文件,或者结合gin框架返回文件流

发布时间 2023-12-10 22:45:55作者: 熊先生不开玩笑
package main

import (
	"errors"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/xuri/excelize/v2"
)

func ReadExcel(file string, sheet string) ([][]string, []string, error) {
	f, err := excelize.OpenFile(file)
	if err != nil {
		return [][]string{}, []string{}, err
	}
	defer func() {
		if err := f.Close(); err != nil {
			fmt.Println(err)
		}
	}()
	sheets := f.GetSheetList()
	// 默认读取第一个sheet
	if sheet == "" {
		sheet = sheets[0]
	}
	rows, er := f.GetRows(sheet)
	if err != nil {
		return [][]string{}, []string{}, er
	}
	header := rows[0]
	rows = rows[1:]
	return rows, header, err
}

// WriteExcel 根据表头和数据写入excel
func WriteExcel(header []string, data [][]interface{}, sheet string, filepath string) error {
	f := excelize.NewFile() // 设置单元格的值
	headerAz, e := GetHeadAZ(len(header))
	if e != nil {
		return e
	}
	// 设置表头
	for key, value := range headerAz {
		f.SetCellValue(sheet, fmt.Sprintf(value+"%d", 1), header[key])
	}
	line := 1
	// 写入数据
	for _, v := range data {
		line++
		index := 0
		for k, vv := range v {
			// 列数据写入不超过表头的列
			if k <= len(header)-1 {
				f.SetCellValue(sheet, fmt.Sprintf(headerAz[index]+"%d", line), vv)
			}
			index++
		}
	}

	// 保存文件
	if err := f.SaveAs(filepath); err != nil {
		return err
	}
	return nil
}

// WriteBuffer 根据表头和数据写入buffer,用gin框架时本方法用来做实时下载
func WriteBuffer(header []string, data [][]interface{}, sheet string, c *gin.Context) error {
	f := excelize.NewFile() // 设置单元格的值
	headerAz, e := GetHeadAZ(len(header))
	if e != nil {
		return e
	}
	// 设置表头
	for key, value := range headerAz {
		f.SetCellValue(sheet, fmt.Sprintf(value+"%d", 1), header[key])
	}
	line := 1
	// 写入数据
	for _, v := range data {
		line++
		index := 0
		for k, vv := range v {
			// 列数据写入不超过表头的列
			if k <= len(header)-1 {
				f.SetCellValue(sheet, fmt.Sprintf(headerAz[index]+"%d", line), vv)
			}
			index++
		}
	}
	err := f.Write(c.Writer)
	if err != nil {
		return err
	}
	return nil
}

func GetAZ() []string {
	var az []string
	var i int
	for {
		az = append(az, string(rune('A'+i)))
		i++
		if i > 25 {
			break
		}
	}
	return az
}

// GetHeadAZ 获取列对应的字母
func GetHeadAZ(length int) ([]string, error) {
	if length > 26*26 {
		return []string{}, errors.New("列数超过限制")
	}
	az := GetAZ()
	if length <= 26 {
		return az[0:length], nil
	}
	arr := az
	for _, value := range az {
		for _, v := range az {
			arr = append(arr, value+v)
			if len(arr) == length {
				goto ret
			}
		}
	}
ret:
	return arr, nil
}