go实现导出excel或csv文件

go实现导出excel或csv文件

很早之前的一个项目需求要,需要把公司信息列表和漏洞信息列表导出excel文件,没有很高要求,能看就行吧,就做了导出csv的两个接口。 最近看我的CSDN发现好久没有写了,惭愧啊!其实遇到的问题,我都有详细记录,自己能看懂,但分享给别人也能看懂就需要好好写了,尽量有空整吧,需要坚持!


实现代码

我把实现代码简单写了一下,是用调用接口的方式实现的,用的gin 包。

最近又有了导出CSV文件的需求,就重新修改了一下这篇文章,根据不同情况分类4类,用4个api来分别请求实现。
第一个接口是这个文章之前的代码,直接返回了文件,请求接口就下载文件,因为在代码里创建了文件。
第二、三、四个接口都是,代码里只返回对应文件格式的数据,需要前端进行处理保存到对应的文件中实现下载。

先说一下优缺点,第一种,需要后端在进程里创建对应的文件保存,最后还要删除掉,如果请求多或文件内容多,都会给后端内存造成很大压力,所以建议使用后面的api,让前端直接获取数据进行保存文件。也要看各自的需求吧,看代码。

Content-Type

下载文件一般要设置对应的文件格式,就是Content-Type ,包括 http 的mime type,知道这个内容的可以跳过直接先看代码,有疑问可以先看下这几篇文章:
1, HTTP Content-Type(MIME List)介绍
2, 阿里云 MIME List 介绍
3, 菜鸟学院 MEMI List 介绍

package main
import (
	"bytes"
	"encoding/csv"
	"fmt"
	"net/http"
	"os"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/tealeg/xlsx"
)

type Server struct {
	engine *gin.Engine
}

func NewServer() *Server {
	ser := &Server{
	    // 用的gin.Default()引擎,自带Logger and Recovery两个中间件,也可以用gin.New(),不带中间件
		engine: gin.Default(),  
	}
	return ser
}

// 这个是为了造数据,可以忽略。
type Student struct {
	ID    string
	Name  string
	Age   string
	Score string
	Addr  string
	Date  string
}
// 造数据的方法
func (s *Server) getData() []*Student {
	res := make([]*Student, 0, 25)

	for i := 1; i <= 20; i++ {
		res = append(res, &Student{
			ID:    fmt.Sprintf("2021000000%d", i),
			Name:  fmt.Sprintf("辣条精-%d", i),
			Age:   fmt.Sprintf("1%d", i),
			Score: fmt.Sprintf("8%d", i),
			Addr:  fmt.Sprintf("辣条小镇太平村-%d号", i),
			Date:  fmt.Sprintf("2012-12-%d", i),
		})
	}
	return res
}

// 这是对应的4个接口,下面会具体说明一下不同接口的作用。
func (s *Server) Start() {
	gin.SetMode(gin.ReleaseMode)
	s.engine.GET("/csv", s.csvApi)              //1,请求后直接下载csv文件
	s.engine.GET("/csv_data", s.saveCSVApi)     //2,请求后,返回csv格式的文件数据byte,需要前端保存到一个对应格式的文件中
	s.engine.GET("/xlsx_data", s.saveXlxsApi)   //3,请求后,返回xlsx格式的文件数据byte,需要前端保存到一个对应格式的文件中
	s.engine.GET("/xlsx_csv", s.saveXlsxCSVApi) //4,请求后,使用xlsx返回csv格式的文件数据byte,需要前端保存到一个对应格式的文件中
	s.engine.Run(":9999")
}

//启动进程
func main() {
	NewServer().Start()
}

// 接口一
// 请求接口后,会直接下载csv格式文件,使用 "encoding/csv" 包实现,代码里直接创建了文件,最后还删除,不然也会给服务器压力,或定期删除。
func (s *Server) csvApi(c *gin.Context) {
	filename, err := s.toCsv()
	if err != nil {
		fmt.Println("t.toCsv() failed == ", err)
	}
	if filename == "" {
		fmt.Println("export excel file failed == ", filename)
	}
	defer func() {
		err := os.Remove("./" + filename)  //下载后,删除文件
		if err != nil {
			fmt.Println("remove  excel file failed", err)
		}
	}()
	c.Writer.Header().Add("Content-Disposition", fmt.Sprintf("attachment; filename=%s", filename))
	c.Writer.Header().Add("Content-Type", "application/octet-stream") //设置下载文件格式,流式下载
	c.File("./" + filename) //直接返回文件
}

// 接口一 function
func (t *Server) toCsv() (string, error) {
    //获取数据
	data := t.getData()
	strTime := time.Now().Format("20060102150405")
	//创建csv文件
	filename := fmt.Sprintf("学生信息-%s.csv", strTime)
	xlsFile, fErr := os.OpenFile("./"+filename, os.O_RDWR|os.O_CREATE, 0766)
	if fErr != nil {
		fmt.Println("Export:created excel file failed ==", fErr)
		return "", fErr
	}
	defer xlsFile.Close()
	//开始写入内容
    //写入UTF-8 BOM,此处如果不写入就会导致写入的汉字乱码
	xlsFile.WriteString("\xEF\xBB\xBF")
	wStr := csv.NewWriter(xlsFile)
	wStr.Write([]string{"学生学号", "学生姓名", "学生年龄", "学生成绩", "家庭地址", "学生生日"})

	for _, s := range data {
		wStr.Write([]string{s.ID, s.Name, s.Age, s.Score, s.Addr, s.Date})
	}
	wStr.Flush()  //写入文件
	return filename, nil
}




// 接口二
// 返回csv文件格式的 []byte数据,使用 "encoding/csv" 包实现,用于导出csv文件。
func (s *Server) saveCSVApi(c *gin.Context) {

	respData, err := s.SetValueToCSV()
	if err != nil {
		fmt.Println("SetValueToCSV failed == ", err.Error())
	}
    //指定下载文件名,可以注释掉,让前端处理文件名
	c.Header("Content-Disposition", "attachment; filename=StudentList.csv") 
	c.Header("Content-Type", "text/csv")  //设置为 .csv 格式文件
	c.Data(http.StatusOK, "text/csv", respData)
}

// 接口二 function
func (t *Server) SetValueToCSV() ([]byte, error) {
	data := t.getData() //获取数据	
   //内容先写入buffer缓存
	buff := new(bytes.Buffer)
	//写入UTF-8 BOM,此处如果不写入就会导致写入的汉字乱码
	buff.WriteString("\xEF\xBB\xBF")
	wStr := csv.NewWriter(buff)
	wStr.Write([]string{"学生学号", "学生姓名", "学生年龄", "学生成绩", "家庭地址", "学生生日"})
	for _, s := range data {
		wStr.Write([]string{s.ID, s.Name, s.Age, s.Score, s.Addr, s.Date})
	}
	wStr.Flush() 
    // 返回[]byte数据
	return buff.Bytes(), nil
}



//接口三
//返回xlsx文件格式的 []byte数据,使用 "github.com/tealeg/xlsx" 包实现,用于导出xlsx文件。
func (s *Server) saveXlxsApi(c *gin.Context) {

	respData, err := s.SetValueToXlsx()
	if err != nil {
		fmt.Println("SetValueToCSV failed == ", err.Error())
	}
	//指定下载文件名,可以注释掉,让前端处理文件名
	c.Header("Content-Disposition", "attachment; filename=StudentList.xlsx") 
	// 设置为 .xlsx格式文件
	c.Header("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
	c.Data(http.StatusOK, "", respData)
}
//接口三 function
func (t *Server) SetValueToXlsx() ([]byte, error) {
	data := t.getData() //获取数据

	var file *xlsx.File
	var sheet *xlsx.Sheet
	var row *xlsx.Row
	var cell *xlsx.Cell
	var err error

	file = xlsx.NewFile()
	sheet, err = file.AddSheet("Sheet1")
	if err != nil {
		fmt.Println("init xlsx file failed, err == ", err.Error())
		return nil, err
	}
	row = sheet.AddRow()
	row.SetHeightCM(1)
	cell = row.AddCell()
	cell.Value = "学生学号"
	cell = row.AddCell()
	cell.Value = "学生姓名"
	cell = row.AddCell()
	cell.Value = "学生年龄"
	cell = row.AddCell()
	cell.Value = "学生成绩"
	cell = row.AddCell()
	cell.Value = "家庭地址"
	cell = row.AddCell()
	cell.Value = "学生生日"

	for _, v := range data {
		row1 := sheet.AddRow()
		cell = row1.AddCell()
		cell.Value = v.ID
		cell = row1.AddCell()
		cell.Value = v.Name
		cell = row1.AddCell()
		cell.Value = v.Age
		cell = row1.AddCell()
		cell.Value = v.Score
		cell = row1.AddCell()
		cell.Value = v.Addr
		cell = row1.AddCell()
		cell.Value = v.Date
	}
	buff := new(bytes.Buffer)
	file.Write(buff)

	return buff.Bytes(), nil
}



//接口四
//返回csv文件格式的 []byte数据,使用 "encoding/csv"包实现,用于导出csv文件。
func (s *Server) saveXlsxCSVApi(c *gin.Context) {
    
    // 还是使用的接口三function 包的方法,
	respData, err := s.SetValueToXlsx()
	if err != nil {
		fmt.Println("SetValueToXlsx failed == ", err.Error())
	}
	//指定下载文件名,可以注释掉,让前端处理文件名
	c.Header("Content-Disposition", "attachment; filename=StudentList.csv") 
	c.Header("Content-Type", "text/csv") //设置为 .csv 格式文件
	c.Data(http.StatusOK, "text/csv", respData)
}

请求测试

接口一

请求地址: http://127.0.0.1:9999/csv,直接在浏览器里请求这个地址即可。
请求后会直接下载导出CSV文件,但是看起来不太好看,有些数据自动被转化了,点击查看的话是没有问题。

go实现导出excel或csv文件_第1张图片

接口二

请求地址:http://127.0.0.1:9999/csv_data ,不能在浏览器直接请求,在Postman测试接口,
在这里插入图片描述
点击Send and Download,会显示保存 .csv 文件,可以选择保存文件目录地址和修改文件名,文件内容和接口一 一样。
go实现导出excel或csv文件_第2张图片

接口三

请求地址:http://127.0.0.1:9999/xlsx_data ,不能在浏览器直接请求,在Postman测试接口,
点击Send and Download,会显示保存 .xlsx 文件,可以选择保存文件目录地址和修改文件名。
go实现导出excel或csv文件_第3张图片go实现导出excel或csv文件_第4张图片

对比之后,可以看到,导出的excel文件,xlsx格式文件比csv格式文件 会更好看一些,可以考虑导出 .xlsx文件, 如果有要求 导出 .csv 格式文件,可以使用接口四,使用xlsx包 实现文件内容,导出.csv 文件,也是可以的,我目前使用的是 接口四。

你可能感兴趣的:(Golang,golang,excel,csv,xlsx,xls)