go标准库和第三方库使用

文章目录

文件处理-os库

用io.Copy()给前端返回字节流

io.Copy(dst Writer, src Reader)字节直接写到文件流

go 复制代码
func (m *FileBiz) DownloadFileV2(ctx *ctrl.Context, fileLink, fileName string) (err error) {

	// 记录下载日志
	record.BusinessLog(record.Debug, "RecordDownloadFileV2", fmt.Sprintf("filePath:%s,wsId:%s,email:%s", fileLink, ctx.GetString("ws_id"), ctx.GetString("email")), "")

	// 获取地址异常
	if fileLink == "" {
		err = errInfo.ErrFilesNull
		return
	}

	// 初始化
	request, err := http.NewRequest("GET", fileLink, nil)
	if err != nil {
		record.BusinessLog(record.Error, "NewRequest", fmt.Sprintf("filePath:%s", fileLink), err.Error())
		err = errInfo.ErrHttpInit
		return
	}

	// 执行请求
	clt := http.Client{}
	resp, err := clt.Do(request)
	if err != nil {
		record.BusinessLog(record.Error, "HttpDp", fmt.Sprintf("filePath:%s", fileLink), err.Error())
		err = errInfo.ErrHttpDo
		return
	}

	defer func(Body io.ReadCloser) {
		errClose := Body.Close()
		if errClose != nil {
			record.BusinessLog(record.Error, "FileClose", fmt.Sprintf("filePath:%s", fileLink), errClose.Error())
		}
	}(resp.Body)

	// 响应头
	ctx.Header("Content-Length", resp.Header.Get("Content-Length"))
	ctx.Header("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", fileName))
	ctx.Header("Content-Type", "application/octet-stream;charset=UTF-8")
	ctx.Header("Set-Cookie", "download=success; Domain=.media.io; Path=/;")

	// 响应流
	written, err := io.Copy(ctx.ResponseWriter(), resp.Body)
	if err != nil {
		record.BusinessLog(record.Error, "IoCopy", fmt.Sprintf("filePath:%s, written:%d", fileLink, written), err.Error())
		err = errInfo.ErrResponseWritten
	}

	return
}

用os来压缩打包文件夹

go 复制代码
// ZipFolder 压缩文件夹并保持目录结构
func ZipFolder(src, dest string) error {
	// 创建目标ZIP文件
	zipFile, err := os.Create(dest)
	if err != nil {
		return err
	}
	defer zipFile.Close()
	// 创建一个ZIP writer
	zipWriter := zip.NewWriter(zipFile)
	defer zipWriter.Close()
	// 遍历源文件夹及其子目录并添加文件到ZIP
	err = filepath.Walk(src, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		// 获取文件的相对路径
		relPath, err := filepath.Rel(src, path)
		if err != nil {
			return err
		}
		// 创建一个新的ZIP文件头
		header, err := zip.FileInfoHeader(info)
		if err != nil {
			return err
		}
		header.Name = filepath.ToSlash(relPath)
		// 如果是目录,需要在名称后添加"/"以便在ZIP中表示为目录
		if info.IsDir() {
			header.Name += "/"
		}
		// 将文件头添加到ZIP中
		writer, err := zipWriter.CreateHeader(header)
		if err != nil {
			return err
		}
		// 如果是目录,不需要写入内容
		if info.IsDir() {
			return nil
		}
		// 打开源文件并将其内容复制到ZIP中
		file, err := os.Open(path)
		if err != nil {
			return err
		}
		defer file.Close()
		_, err = io.Copy(writer, file)
		return err
	})
	return err
}

压缩后通过context.SendFile来发送

go 复制代码
func (m *FileBiz) PixpicBatchDownloadFile(ctx *ctrl.Context, taskId string) (err error) {
	task, err := m.pixpicTaskModel.GetOne("task_id", taskId)
	if err != nil {
		record.BusinessLog(record.Error, "GetOne", fmt.Sprintf("taskId:%s", taskId), err.Error())
		err = errInfo.ErrDBGetTask
		return
	}

	// 获取资源信息
	resourcesInput, err := m.pixpicResourceModel.GetInputs(task.TaskId)
	if err != nil {
		record.BusinessLog(record.Error, "GetOneInput", fmt.Sprintf("taskId:%s", task.ID), err.Error())
		err = errInfo.ErrDBGetResource
		return
	}

	// 创建文件夹,规则:taskid_template,以及子目录input,output
	destName := fmt.Sprintf("%s_%s", taskId, task.Template) // url.QueryEscape
	destPath := fmt.Sprintf("%s/%s", "download", destName)
	subPathList := []string{
		fmt.Sprintf("%s/%s", destPath, "input"),
	}

	if task.Status == TaskStatusSuccess {
		subPathList = append(subPathList, fmt.Sprintf("%s/%s", destPath, "output"))
	}

	_, errPath := os.Stat(destPath)
	if errPath != nil {
		err = os.Mkdir(destPath, os.ModePerm)
		if err != nil {
			record.BusinessLog(record.Error, "OsMkdir", fmt.Sprintf("destPath:%s", destPath), err.Error())
			err = errInfo.ErrMkDir
			return
		}
		for _, val := range subPathList {
			_, errsubPath := os.Stat(val)
			if errsubPath != nil {
				err = os.Mkdir(val, os.ModePerm)
				if err != nil {
					record.BusinessLog(record.Error, "OsMkdir", fmt.Sprintf("destSubPath:%s", val), err.Error())
					err = errInfo.ErrMkDir
					return
				}
			}
		}
	}

	// 删除临时文件夹及文件
	defer func(path string) {
		errR := os.RemoveAll(path)
		if errR != nil {
			record.BusinessLog(record.Error, "OsRemoveAll", fmt.Sprintf("destPath:%s", path), errR.Error())
			return
		}
		record.BusinessLog(record.Info, "OsRemoveAll", fmt.Sprintf("destPath:%s", path), "ok")
	}(destPath)

	// 写入资源
	srv := service.GetStorageService()
	for _, val := range resourcesInput {
		tmpList := strings.Split(val.Url, "/")
		suffix := "_false"
		if val.Status == 1 {
			suffix = "_true"
		}
		fileName := tmpList[len(tmpList)-1]
		index := strings.LastIndex(fileName, ".")
		if index > 0 {
			fileName = fileName[:index] + suffix + fileName[index:]
		}
		filePath := fmt.Sprintf("%s/%s", subPathList[0], fileName)
		signUrl := srv.GetSignUrl(context.TODO(), val.Url, 0)
		errDF := oss.DownloadFile2(signUrl, filePath)
		if errDF != nil {
			record.BusinessLog(record.Error, "DownloadFile2", fmt.Sprintf("download err,file: %s, taskId:%s", signUrl, taskId), err.Error())
			continue
		}
	}

	if task.Status == TaskStatusSuccess {
		resourcesOutput, err2 := m.pixpicResourceModel.GetOutputs(task.TaskId, 100)
		if err2 != nil {
			record.BusinessLog(record.Error, "GetOneOutput", fmt.Sprintf("taskId:%s", task.ID), err.Error())
			err2 = errInfo.ErrDBGetResource
			return err2
		}

		for _, val := range resourcesOutput {
			tmpList := strings.Split(val.Url, "/")
			fileName := tmpList[len(tmpList)-1]
			filePath := fmt.Sprintf("%s/%s", subPathList[1], fileName)
			signUrl := srv.GetSignUrl(context.TODO(), val.Url, 0)
			errDF := oss.DownloadFile2(signUrl, filePath)
			if errDF != nil {
				record.BusinessLog(record.Error, "DownloadFile2", fmt.Sprintf("download err,file: %s, taskId:%s", signUrl, taskId), err.Error())
				continue
			}
		}
		filePath := fmt.Sprintf("%s/%s.safetensors", destPath, taskId)
		signUrl := srv.GetSignUrl(context.TODO(), fmt.Sprintf("pixpic/models/%s/%s.safetensors", taskId, taskId), 0)
		errDF := oss.DownloadFile2(signUrl, filePath)
		if errDF != nil {
			record.BusinessLog(record.Error, "DownloadFile2", fmt.Sprintf("download err,file: %s, taskId:%s", signUrl, taskId), err.Error())
		}
	}

	// 打包文件
	downloadFileName := fmt.Sprintf("%s.zip", destName)
	downloadFilePath := fmt.Sprintf("%s", downloadFileName)
	err = zip.ZipFolder(destPath, downloadFilePath)
	if err != nil {
		record.BusinessLog(record.Error, "ZipZip", fmt.Sprintf("downloadFilePath:%s", downloadFilePath), err.Error())
		err = errInfo.ErrZip
		return
	}

	// 下载
	downloadFileName = strings.ReplaceAll(downloadFileName, ",", "+")
	err = ctx.SendFile(downloadFilePath, downloadFileName)
	if err != nil {
		record.BusinessLog(record.Error, "SendFile", fmt.Sprintf("downloadFilePath:%s downloadFileName:%s", downloadFilePath, downloadFileName), err.Error())
		err = errInfo.ErrSendFile
		return
	}

	return
}

读写excel-excelize库

windows下最高支持 github.com/xuri/excelize/[email protected]版本

例1-基础的读和写

go 复制代码
func pushEmail(excel_input string, excel_result string, survey_name string) {
	f, err := excelize.OpenFile(excel_input)
	if err != nil {
		fmt.Println(err)
		return
	}
	defer func() {
		if err := f.Close(); err != nil {
			fmt.Println(err)
		}
	}()

	emails := make([]string, 0)

	rows, err := f.Rows("Sheet1")
	if err != nil {
		fmt.Println(err)
		return
	}
	for rows.Next() {
		row, err := rows.Columns()
		if err != nil {
			fmt.Println(err)
		}
		if len(row) > 0 {
			emails = append(emails, row[0])
		}
	}
	if err = rows.Close(); err != nil {
		fmt.Println(err)
	}
	//fmt.Println(emails)

	fWrite := excelize.NewFile()
	defer func() {
		if err := fWrite.Close(); err != nil {
			fmt.Println(err)
		}
	}()

	streamWriter, err := fWrite.NewStreamWriter("Sheet1")
	if err != nil {
		fmt.Println(err)
		return
	}

	streamWriter.SetRow("A1", []interface{}{"email", "flag"})

	for i := 1; i < len(emails); i++ {
		//fmt.Println(emails[i])
		email, flag := PushUserEmail2(emails[i], survey_name, "FamiSafe", nil)

		if flag == string("0") {
			fmt.Println(email)
			fmt.Println(flag)
			break
		}
		axis, _ := excelize.CoordinatesToCellName(1, i+1)
		streamWriter.SetRow(axis, []interface{}{email, flag})
	}
	if err = streamWriter.Flush(); err != nil {
		fmt.Println(err)
		return
	}
	fWrite.SaveAs(excel_result)
}

例2-写多个Sheet数据到excel

go 复制代码
package user

import (
	"bufio"
	"bytes"
	"context"
	"fmt"
	"github.com/gogf/gf/errors/gerror"
	"github.com/gogf/gf/frame/g"
	"github.com/xuri/excelize/v2"
	s "pxgit.300624.cn/gaea-server/x/core/storage"
	"pxgit.300624.cn/pixso-service/pixso-service-web/app/dao"
	"pxgit.300624.cn/pixso-service/pixso-service-web/app/define"
	"pxgit.300624.cn/pixso-service/pixso-service-web/app/service/msg"
	"pxgit.300624.cn/pixso-service/pixso-service-web/common/intranet/statistics"
	"pxgit.300624.cn/pixso-service/pixso-service-web/common/intranet/user"
	"pxgit.300624.cn/pixso-service/pixso-service-web/common/tool/logger"
	"pxgit.300624.cn/pixso-service/pixso-service-web/common/tool/storage"
	"pxgit.300624.cn/pixso-service/pixso-service-web/common/tool/utils"
	"sort"
	"strconv"
)

func ExportExportEntActive(ctx context.Context, req *define.UserExportActiveStatReq) error {
	subInfo := &define.ExportStatInfo{
		UserId:             req.UserId,
		SpaceId:            req.SpaceId,
		Id:                 req.Id,
		FileNameWithSuffix: fmt.Sprintf("%s.xlsx", req.FileName),
	}
	f, err := ExportEntActiveToExcel(ctx, req)
	if err != nil {
		logger.BaseLog().Errorf("ExportExportEntActive.ExportEntActiveToExcel, err:%+v", err)
		err2 := dao.EntExportQueue.UpdateInterface(ctx, req.Id, g.Map{dao.EntExportQueue.Columns.ExportStatus: statistics.ExportFail})
		if err2 != nil {
			return err2
		}
		subInfo.ExportStatus = statistics.ExportFail
		msg.UserExportStatMsg(ctx, subInfo)
		return err
	}

	var b bytes.Buffer

	writer := bufio.NewWriter(&b)
	err = f.Write(writer)
	if err != nil {
		return err
	}
	var EXLHeader = map[string]interface{}{"Content-FileType": storage.TypeFile, "content-type": storage.TypeFile,
		s.HeaderContentDisposition: fmt.Sprintf("attachment;filename=%s.xlsx", req.FileName)} // 存储时header头带上"Content-Disposition",存二进制文件的后缀格式
	objectId, err := storage.Public().NewObject(ctx, "xlsx", int64(b.Len()), EXLHeader, &b)
	if err != nil {
		logger.BaseLog().Errorf("ExportExportEntActive.storage.NewObject, err:%+v", err)
		return gerror.Wrap(err, "ExportExportEntActive.storage.NewObject")
	}
	err = dao.EntExportQueue.UpdateInterface(ctx, req.Id, g.Map{dao.EntExportQueue.Columns.ExportStatus: statistics.ExportSuccess,
		dao.EntExportQueue.Columns.ObjectKey: objectId})
	if err != nil {
		return err
	}

	subInfo.ExportStatus = statistics.ExportSuccess
	fileUrl, err := storage.Public().SignUrl(ctx, objectId, 60*60*24*7)
	if err != nil {
		logger.BaseLog().Errorf("ExportExportEntActive.storage.SignUrl, err:%+v", err)
		return gerror.Wrap(err, "ExportExportEntActive.storage.SignUrl")
	}
	subInfo.FileUrl = fileUrl
	msg.UserExportStatMsg(ctx, subInfo)
	return nil
}

func ExportEntActiveToExcel(ctx context.Context, req *define.UserExportActiveStatReq) (*excelize.File, error) {
	userActive := &statistics.InnerEntUserActiveArgs{
		Product:      statistics.ProductPixso,
		IntervalType: statistics.InterValDay,
		StartTime:    req.StartTime,
		EndTime:      req.EndTime,
		SpaceId:      req.SpaceId,
	}
	userEdit := &statistics.InnerEntUserEditArgs{
		Product:      statistics.ProductPixso,
		IntervalType: statistics.InterValDay,
		StartTime:    req.StartTime,
		EndTime:      req.EndTime,
		SpaceId:      req.SpaceId,
		ObjType:      statistics.PixsoDesignFile,
	}

	f := excelize.NewFile()
	defer func() {
		if err := f.Close(); err != nil {
			fmt.Println(err)
		}
	}()

	// 1 概况sheet
	// 活跃天数
	entUserActiveInfoResp, err := statistics.NewStatCenter().EntUserActiveInfo(userActive)
	if err != nil {
		return nil, err
	}
	userIdList := make([]uint64, 0) // userlist排序下
	for k := range entUserActiveInfoResp.EntUserActiveInfo {
		userIdList = append(userIdList, k)
	}
	sort.Sort(utils.Uint64Slice(userIdList))

	// 设计文件编辑活跃天数、设计文件总编辑时长
	entUserEditInfoResp, err := statistics.NewStatCenter().EntUserEditInfo(userEdit)
	if err != nil {
		return nil, err
	}
	// 账号、用户名、席位信息
	uMap, err := user.MapById(ctx, userIdList)
	if err != nil {
		return nil, err
	}
	flMap, err := dao.UserTag.FileLevelMap(ctx, req.SpaceId, userIdList)
	if err != nil {
		return nil, err
	}

	sheetName := req.SheetNames[0]
	f.NewSheet(sheetName)
	streamWriter, err := f.NewStreamWriter(sheetName)
	if err != nil {
		return nil, gerror.Wrap(err, "WriteToSheet.NewStreamWriter")
	}
	columnNamesInterface := make([]interface{}, 0)
	for _, c := range req.SheetColumnMap[sheetName] {
		columnNamesInterface = append(columnNamesInterface, c)
	}
	streamWriter.SetRow("A1", columnNamesInterface)
	for i, userId := range userIdList {
		account := ""
		if len(uMap[userId].UniqueId) > 0 {
			account = uMap[userId].UniqueId
		} else if len(uMap[userId].Mobile) > 0 {
			account = uMap[userId].Mobile
		} else if len(uMap[userId].Email) > 0 {
			account = uMap[userId].Email
		}
		fileLevelString := strconv.FormatUint(uint64(flMap[userId]), 10)
		if v, ok := req.FileLevelMap[flMap[userId]]; ok {
			fileLevelString = v
		}
		row := []interface{}{account, uMap[userId].NickName, fileLevelString, entUserActiveInfoResp.EntUserActiveInfo[userId],
			entUserEditInfoResp.EntUserEditInfo[userId].ActiveDay, entUserEditInfoResp.EntUserEditInfo[userId].Duration}
		axis, _ := excelize.CoordinatesToCellName(1, i+2)
		streamWriter.SetRow(axis, row)
	}
	if err = streamWriter.Flush(); err != nil {
		return nil, gerror.Wrap(err, "WriteToSheet.Flush ")
	}

	// 2 活跃用户数sheet
	entUserActiveTrendResp, err := statistics.NewStatCenter().EntUserActiveTrend(userActive)
	if err != nil {
		return nil, err
	}
	dateList := make([]string, 0, len(entUserActiveTrendResp.EntUserActiveTrend))
	for k := range entUserActiveTrendResp.EntUserActiveTrend {
		dateList = append(dateList, k)
	}
	sort.Sort(utils.StringSlice(dateList))
	sheetName = req.SheetNames[1]
	f.NewSheet(sheetName)
	streamWriter, err = f.NewStreamWriter(sheetName)
	if err != nil {
		return nil, gerror.Wrap(err, "WriteToSheet.NewStreamWriter")
	}
	columnNamesInterface1 := make([]interface{}, 0)
	for _, c := range req.SheetColumnMap[sheetName] {
		columnNamesInterface1 = append(columnNamesInterface1, c)
	}
	streamWriter.SetRow("A1", columnNamesInterface1)
	for i, date := range dateList {
		row := []interface{}{date, entUserActiveTrendResp.EntUserActiveTrend[date]}
		axis, _ := excelize.CoordinatesToCellName(1, i+2)
		streamWriter.SetRow(axis, row)
	}
	if err = streamWriter.Flush(); err != nil {
		return nil, gerror.Wrap(err, "WriteToSheet.Flush ")
	}

	// 3 设计文件编辑人数sheet
	entUserEditTrendResp, err := statistics.NewStatCenter().EntUserEditTrend(userEdit)
	if err != nil {
		return nil, err
	}
	dateList = make([]string, 0, len(entUserEditTrendResp.EntUserEditUserTrend))
	for k := range entUserEditTrendResp.EntUserEditUserTrend {
		dateList = append(dateList, k)
	}
	sort.Sort(utils.StringSlice(dateList))
	sheetName = req.SheetNames[2]
	f.NewSheet(sheetName)
	streamWriter, err = f.NewStreamWriter(sheetName)
	if err != nil {
		return nil, gerror.Wrap(err, "WriteToSheet.NewStreamWriter")
	}
	columnNamesInterface2 := make([]interface{}, 0)
	for _, c := range req.SheetColumnMap[sheetName] {
		columnNamesInterface2 = append(columnNamesInterface2, c)
	}
	streamWriter.SetRow("A1", columnNamesInterface2)
	for i, date := range dateList {
		row := []interface{}{date, entUserEditTrendResp.EntUserEditUserTrend[date]}
		axis, _ := excelize.CoordinatesToCellName(1, i+2)
		streamWriter.SetRow(axis, row)
	}
	if err = streamWriter.Flush(); err != nil {
		return nil, gerror.Wrap(err, "WriteToSheet.Flush ")
	}

	// 4 设计文件人均编辑时长sheet
	dateList = make([]string, 0, len(entUserEditTrendResp.EntUserEditTrend))
	for k := range entUserEditTrendResp.EntUserEditTrend {
		dateList = append(dateList, k)
	}
	sort.Sort(utils.StringSlice(dateList))
	sheetName = req.SheetNames[3]
	f.NewSheet(sheetName)
	streamWriter, err = f.NewStreamWriter(sheetName)
	if err != nil {
		return nil, gerror.Wrap(err, "WriteToSheet.NewStreamWriter")
	}
	columnNamesInterface3 := make([]interface{}, 0)
	for _, c := range req.SheetColumnMap[sheetName] {
		columnNamesInterface3 = append(columnNamesInterface3, c)
	}
	streamWriter.SetRow("A1", columnNamesInterface3)
	for i, date := range dateList {
		row := []interface{}{date, entUserEditTrendResp.EntUserEditTrend[date]}
		axis, _ := excelize.CoordinatesToCellName(1, i+2)
		streamWriter.SetRow(axis, row)
	}
	if err = streamWriter.Flush(); err != nil {
		return nil, gerror.Wrap(err, "WriteToSheet.Flush ")
	}

	// 删除默认工作表
	f.DeleteSheet("Sheet1")
	// 设置工作簿的默认工作表
	f.SetActiveSheet(0)
	return f, nil
}

func WriteToFile(fileName string, sheetNames []string, m map[string]*define.SheetInfo) (*excelize.File, error) {
	f := excelize.NewFile()
	defer func() {
		if err := f.Close(); err != nil {
			fmt.Println(err)
		}
	}()
	for _, sheetName := range sheetNames {
		if v, ok := m[sheetName]; ok {
			err := WriteToSheet(f, sheetName, v.ColumnNames, v.SheetRows)
			if err != nil {
				return nil, err
			}
		}
	}
	// 删除默认工作表
	f.DeleteSheet("Sheet1")
	// 设置工作簿的默认工作表
	f.SetActiveSheet(0)

	var b bytes.Buffer

	writer := bufio.NewWriter(&b)
	err := f.Write(writer)
	if err != nil {
		return nil, err
	}
	var EXLHeader = map[string]interface{}{"Content-FileType": storage.TypeFile, "content-type": storage.TypeFile,
		s.HeaderContentDisposition: fmt.Sprintf("attachment;filename=%s", fileName)}
	objectId, err := storage.Public().NewObject(context.TODO(), "xlsx", int64(b.Len()), EXLHeader, &b)
	fmt.Println(storage.Public().SignUrl(context.TODO(), objectId, 60*60*24*7))

	if err != nil {
		fmt.Println("storage err!!!")
		return nil, gerror.Wrap(err, "storage err!!!")
	}

	return f, nil
}

func WriteToSheet(f *excelize.File, sheetName string, columnNames []string, rows [][]interface{}) error {
	f.NewSheet(sheetName)
	streamWriter, err := f.NewStreamWriter(sheetName)
	if err != nil {
		return gerror.Wrap(err, "WriteToSheet.NewStreamWriter")
	}
	columnNamesInterface := make([]interface{}, 0)
	for _, c := range columnNames {
		columnNamesInterface = append(columnNamesInterface, c)
	}
	streamWriter.SetRow("A1", columnNamesInterface)
	for i, row := range rows {
		axis, _ := excelize.CoordinatesToCellName(1, i+2)
		streamWriter.SetRow(axis, row)
	}
	if err = streamWriter.Flush(); err != nil {
		return gerror.Wrap(err, "WriteToSheet.Flush ")
	}

	return nil
}
相关推荐
Asthenia041232 分钟前
Spring扩展点与工具类获取容器Bean-基于ApplicationContextAware实现非IOC容器中调用IOC的Bean
后端
bobz9651 小时前
ovs patch port 对比 veth pair
后端
Asthenia04121 小时前
Java受检异常与非受检异常分析
后端
uhakadotcom1 小时前
快速开始使用 n8n
后端·面试·github
JavaGuide1 小时前
公司来的新人用字符串存储日期,被组长怒怼了...
后端·mysql
bobz9652 小时前
qemu 网络使用基础
后端
Asthenia04122 小时前
面试攻略:如何应对 Spring 启动流程的层层追问
后端
Asthenia04122 小时前
Spring 启动流程:比喻表达
后端
Asthenia04123 小时前
Spring 启动流程分析-含时序图
后端
ONE_Gua3 小时前
chromium魔改——CDP(Chrome DevTools Protocol)检测01
前端·后端·爬虫