go 操作 Excel
文档地址:
https://xuri.me/excelize/zh-hans/
package main
import (
"fmt"
"github.com/xuri/excelize/v2"
)
func main() {
readEecel()
//writeEecel()
//appendEecel()
}
func writeEecel() {
f := excelize.NewFile()
// 创建一个工作表
index := f.NewSheet("Sheet1")
// 设置单元格的值
f.SetCellValue("Sheet1", "A2", "Hello world.")
f.SetCellValue("Sheet1", "B2", 100)
//按行赋值
err := f.SetSheetRow("Sheet1", "A1", &[]interface{}{"39 - 38 = ", "39 - 38 = ", "39 - 38 = ", "39 - 38 = ", "39 - 38 = "})
if err != nil {
fmt.Println(err)
}
//设置列宽度
err = f.SetColWidth("Sheet1", "A", "H", 16)
if err != nil {
fmt.Println(err)
}
// 设置工作簿的默认工作表
f.SetActiveSheet(index)
// 根据指定路径保存文件
if err = f.SaveAs("Book1.xlsx"); err != nil {
fmt.Println(err)
}
}
func appendEecel() {
fileName := "Book1.xlsx"
activeSheet := "Sheet1"
f, _:= excelize.OpenFile(fileName)
// Get all the rows in the Sheet1.获取所有行的数据 按行获取
rows, err := f.GetRows(activeSheet)
//获取所有列的内容 按列获取
cols, err := f.GetCols(activeSheet)
if err != nil {
fmt.Println(err)
return
}
fmt.Println("rows_len:", len(rows))
fmt.Println("cols_len:", len(cols))
//fmt.Println("rows_content:",rows)
lineHeight, err := f.GetRowHeight(activeSheet,1)
fmt.Println("lineHeight:", lineHeight)
lineLevel, err := f.GetRowOutlineLevel(activeSheet,2)
fmt.Println("lineLevel:", lineLevel)
f.SetCellValue(activeSheet, fmt.Sprintf("A%d",len(rows)+1), fmt.Sprintf("aa%d",len(rows)+1))
f.SetCellValue(activeSheet, fmt.Sprintf("B%d",len(rows)+1), fmt.Sprintf("bb%d",len(rows)+1))
f.SetCellValue(activeSheet, fmt.Sprintf("C%d",len(rows)+1), fmt.Sprintf("cc%d",len(rows)+1))
if err := f.SaveAs(fileName); err != nil {
fmt.Println(err)
}
}
func readEecel() {
//f, err := excelize.OpenFile("Book1.xlsx")
f, err := excelize.OpenFile("信息系统暴露面模板_20211027.xlsx")
if err != nil {
fmt.Println(err)
return
}
defer func() {
if err := f.Close(); err != nil {
fmt.Println(err)
}
}()
// 获取工作表中指定单元格的值
//cell, err := f.GetCellValue("Sheet1", "B2")
//if err != nil {
// fmt.Println(err)
// return
//}
//fmt.Println(cell)
// 获取 Sheet1 上所有单元格
rows, err := f.GetRows("Sheet1")
if err != nil {
fmt.Println(err)
return
}
for _, row := range rows {
for _, colCell := range row {
fmt.Print(colCell, "\t")
}
fmt.Println()
}
fmt.Println("===========================================")
res:= arrayTwoStringGroupsOf(rows,3)
fmt.Println(res)
}
func arrayTwoStringGroupsOf(arr [][]string, num int64) [][][]string {
max := int64(len(arr))
//判断数组大小是否小于等于指定分割大小的值,是则把原数组放入二维数组返回
if max <= num {
return [][][]string{arr}
}
//获取应该数组分割为多少份
var quantity int64
if max%num == 0 {
quantity = max / num
} else {
quantity = (max / num) + 1
}
//声明分割好的二维数组
var segments = make([][][]string, 0)
//声明分割数组的截止下标
var start, end, i int64
for i = 1; i <= quantity; i++ {
end = i*num
if i != quantity {
segments = append(segments, arr[start:end])
} else {
segments = append(segments, arr[start:])
}
start = i*num
}
return segments
}
func arrayInGroupsOf(arr []int, num int64) [][]int {
max := int64(len(arr))
//判断数组大小是否小于等于指定分割大小的值,是则把原数组放入二维数组返回
if max <= num {
return [][]int{arr}
}
//获取应该数组分割为多少份
var quantity int64
if max%num == 0 {
quantity = max / num
} else {
quantity = (max / num) + 1
}
//声明分割好的二维数组
var segments = make([][]int, 0)
//声明分割数组的截止下标
var start, end, i int64
for i = 1; i <= quantity; i++ {
end = i*num
if i != quantity {
segments = append(segments, arr[start:end])
} else {
segments = append(segments, arr[start:])
}
start = i*num
}
return segments
}
应用场景:
gorm 从 mysql 里分批查出数据,并分批追加写入excel
// 全量excel分批导出poc
func (e *ModelExploits) ExportModelExploits(c *gin.Context) {
msgID := tools.GenerateMsgIDFromContext(c)
d := new(dto.ModelExploitsSearch)
//fmt.Println("d222", d)
db, err := tools.GetOrm(c)
if err != nil {
log.Error(err)
return
}
//查询列表
err = d.Bind(c)
if err != nil {
e.Error(c, http.StatusUnprocessableEntity, err, "参数验证失败")
return
}
//数据权限检查
p := actions.GetPermissionFromContext(c)
serviceStudent := service.ModelExploits{}
serviceStudent.MsgID = msgID
serviceStudent.Orm = db
fileNamePath, err := serviceStudent.ExportModelExploitsPage(d, p)
if err != nil {
e.Error(c, http.StatusUnprocessableEntity, err, "查询失败")
return
}
e.OK(c, gin.H{"filePath": fileNamePath}, "ok")
}
func (e *ModelExploits) ExportModelExploitsPage(c *dto.ModelExploitsSearch, p *actions.DataPermission) (fileNamePath string, err error) {
//var err error
var data models.ModelExploits
msgID := e.MsgID
dirPath := "static/downloads" //导出的目录
fileName := fmt.Sprintf("%s_%s", time.Now().Format("20060102150405"), "poc_data.xlsx") //文件名称
fileNamePath = path.Join(dirPath, fileName) //文件全路径
batchSize := 100
var lis []models.ModelExploits
result := e.Orm.Model(&data).
Scopes(
cDto.MakeCondition(c.GetNeedSearch()),
//cDto.Paginate(c.GetPageSize(), c.GetPageIndex()),
actions.Permission(data.TableName(), p),
).
//分批处理
FindInBatches(&lis, batchSize, func(tx *gorm.DB, batch int) error {
// 批量处理找到的记录
total := 0
if len(lis) == batchSize {
total = batch * batchSize
} else {
total = (batch-1)*batchSize + len(lis)
}
fmt.Printf("第 %d 批 , 每批 %d 条 ,已经处理 %d 条\n", batch, batchSize, total) // batch // Batch 1, 2, 3
//for _, result := range lis {
// fmt.Println(result.Id)
//}
// 批量处理找到的记录 分批存到excel里
err := appendSaveEexcel(dirPath, fileName, &lis)
if err != nil {
return err
}
//tx.Save(&lis)
//fmt.Println(tx.RowsAffected) // 本次批量操作影响的记录数
// 如果返回错误会终止后续批量操作
return nil
})
if result.Error != nil {
log.Errorf("msgID[%s] db error:%s", msgID, result.Error)
return "", result.Error
}
//fmt.Printf("total4444---->:%d", len(lis)) // batch // Batch 1, 2, 3
//fmt.Println(result.Error) // returned error
//fmt.Println(result.RowsAffected) // 整个批量操作影响的记录数
return fileNamePath, nil
}
//save excel 追加写入
func appendSaveEexcel(dirPath, fileName string, lists *[]models.ModelExploits) error {
_ = tools.PathDirCreate(dirPath) //不存在创建目录
activeSheetName := "Sheet1"
fileNamePath := path.Join(dirPath, fileName)
exists, err := tools.PathFileExists(fileNamePath) //判断文件是否存在创建目录
rowNum := 0
lastLineNum := 0
var f *excelize.File
// 创建excel
if !exists || err != nil {
f = excelize.NewFile()
// Create a new sheet.
index := f.NewSheet(activeSheetName)
// Set active sheet of the workbook.
f.SetActiveSheet(index)
// Set tabletitle value of a cell.
tableInfo := map[string]string{
"A1": "Id",
"B1": "Filename",
"C1": "Product",
"D1": "Fofaquery",
}
for k, v := range tableInfo {
f.SetCellValue(activeSheetName, k, v)
}
} else { // 追加写入excel
f, _ = excelize.OpenFile(fileNamePath)
rows, _ := f.GetRows(activeSheetName)
lastLineNum = len(rows) //找到最后一行
}
// Set table content value of a cell.
for index, list := range *lists {
if !exists || err != nil {
//如果不存在从第2行写入
rowNum = index + 2
} else {
//否则从文件内容尾行写入
rowNum = lastLineNum + index + 1
}
f.SetCellValue(activeSheetName, fmt.Sprintf("A%d", rowNum), list.Id)
f.SetCellValue(activeSheetName, fmt.Sprintf("B%d", rowNum), list.Filename)
f.SetCellValue(activeSheetName, fmt.Sprintf("C%d", rowNum), list.Product)
f.SetCellValue(activeSheetName, fmt.Sprintf("D%d", rowNum), list.Fofaquery)
}
// Save spreadsheet by the given path. static/downloads/Book1.xlsx
if err := f.SaveAs(fileNamePath); err != nil {
fmt.Println(err)
return errors.New(fmt.Sprintf("save file failed, path:(%s)", fileNamePath))
}
return nil
}
封装
/*
dirPath := "log"
fileName := "Book1.xlsx"
dataList := [][]interface{}{{"姓名", "电话", "公司", "职位", "加入时间"}, {1, 2, "刘犇,刘犇,刘犇", "4", "5"}}
AppendSaveExcel(dirPath, fileName, &dataList) //会存到log/Book1.xlsx里
文件没有创建并写入,有追加写
*/
func AppendSaveExcel(dirPath, fileName string, dataList *[][]interface{}) (err error) {
if len(*dataList) == 0 {
return errors.New("数据不能为空")
}
//不存在创建目录
_ = CreateFolder(dirPath, true)
activeSheetName := "Sheet1"
//文件路径
fileNamePath := path.Join(dirPath, fileName)
// 从第几行开始写数据
rowNum := 0
// excel最后数据所有行数
lastLineNum := 0
var f *excelize.File
// 创建excel
//判断文件是否存在,不存在新建
fileExistsBool := FileExists(fileNamePath)
if !fileExistsBool {
f = excelize.NewFile()
} else { // 追加写入excel
f, _ = excelize.OpenFile(fileNamePath)
rows, _ := f.GetRows(activeSheetName)
lastLineNum = len(rows) //找到最后一行
}
// Create a new sheet.
index := f.NewSheet(activeSheetName)
// 设置工作簿的默认工作表
f.SetActiveSheet(index)
//设置列宽度为16
var ColAbc = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
//需要存入数据的列长度
dataColLen := len((*dataList)[0])
if dataColLen > 26 {
err = f.SetColWidth("Sheet1", "A", "Z", 16)
} else {
err = f.SetColWidth("Sheet1", "A", ColAbc[dataColLen-1:dataColLen], 16)
}
if err != nil {
fmt.Println(err)
return errors.New(fmt.Sprintf("f.SetColWidth failed, err:%v", err))
}
// 从文件内容尾行写入
rowNum = lastLineNum
// 循环按行赋值
for _, list := range *dataList {
rowNum += 1
//按行赋值 从aN开始按行赋值
f.SetSheetRow(activeSheetName, fmt.Sprintf("A%d", rowNum), &list)
}
// 保存excel
if err := f.SaveAs(fileNamePath); err != nil {
fmt.Println(err)
return errors.New(fmt.Sprintf("save file failed, path:(%s)", fileNamePath))
}
return nil
}
func CreateFolder(p string, ignoreExists bool) error {
if FolderExists(p) == true && ignoreExists == false {
err := errors.New("folder exists")
return err
}
if FolderExists(p) == false {
err := os.MkdirAll(p, os.ModePerm)
if err != nil {
return err
}
}
return nil
}
func FileExists(filename string) bool {
info, err := os.Stat(filename)
if os.IsNotExist(err) {
return false
}
if info == nil {
return false
}
return true
}
go 操作 Excel的更多相关文章
- 免费高效实用的.NET操作Excel组件NPOI(.NET组件介绍之六)
很多的软件项目几乎都包含着对文档的操作,前面已经介绍过两款操作文档的组件,现在介绍一款文档操作的组件NPOI. NPOI可以生成没有安装在您的服务器上的Microsoft Office套件的Excel ...
- C#通过NPOI操作Excel
参考页面: http://www.yuanjiaocheng.net/webapi/create-crud-api-1-post.html http://www.yuanjiaocheng.net/w ...
- POI操作Excel
POI和Excel简介 JAVA中操作Excel的有两种比较主流的工具包: JXL 和 POI .jxl 只能操作Excel 95, 97, 2000也即以.xls为后缀的excel.而poi可以操作 ...
- NPOI操作EXCEL(六)——矩阵类表头EXCEL模板的解析
哈哈~~~很高兴还活着.总算加班加点的把最后一类EXCEL模板的解析做完了... 前面几篇文章介绍了博主最近项目中对于复杂excel表头的解析,写得不好,感谢园友们的支持~~~ 今天再简单讲诉一下另一 ...
- VB操作EXCEL文件
用VB操作Excel(VB6.0)(整理) 首先创建Excel对象,使用ComObj:Dim ExcelID as Excel.ApplicationSet ExcelID as new Excel. ...
- VB.NET操作Excel
VB.NET操作Excel的基本方法与例子:
- C# 操作excel单元格居中
C# 操作excel //导出Excel private void ExportExcel(string fileName, System.Data.DataTable myDGV, s ...
- NPOI操作Excel辅助类
/// <summary> /// NPOI操作excel辅助类 /// </summary> public static class NPOIHelper { #region ...
- JAVA的POI操作Excel
1.1Excel简介 一个excel文件就是一个工作簿workbook,一个工作簿中可以创建多张工作表sheet,而一个工作表中包含多个单元格Cell,这些单元格都是由列(Column)行(Row)组 ...
- NPOI操作EXCEL(一)——npoi基础
去年项目有一个子模块需要解析上百张不一样的excel表格入库,当时用的NPOI,做了很久...也尝试想把代码分享到oschina,结果没坚持两篇就放弃了. 赶巧的是,昨天运营那边提出要录入一些基础数据 ...
随机推荐
- 终于来了!FastGPT 正式兼容 GPT 应用
终于来了!FastGPT 正式兼容 GPT 应用 FastGPT V4.7 正式加入了工具调用功能,可以兼容 GPTs 的 Actions.这意味着,你可以直接导入兼容 GPTs 的 Agent 工具 ...
- Python列表list 分片实例
1 a = list(range(10)) 2 print(a[::]) #复制一个列表 3 print(a[::2]) #每隔2个取一次 4 print(a[::3]) #每隔3个取一次 5 6 p ...
- MybatisPlus的那些坑
1.实体类属性会被错误解析,需要加上注解@TableField @TableField("front_of_id_card") //身份证正面 private String fro ...
- Jetty的ssl模块
启用ssl模块,执行如下命令: java -jar $JETTY_HOME/start.jar --add-modules=ssl 命令的输出,如下: INFO : ssl initialized i ...
- HMS Core打造影音娱乐行业解决方案,助推视听新浪潮
6月28日,HDD·HMS Core. Sparkle影音娱乐线上沙龙在各大直播平台与开发者们见面.本次线上沙龙围绕影音娱乐行业现状观察和趋势.用户数据洞察分析以及HMS Core影音娱乐行业解决方案 ...
- Qt调用动态库的三种方式(linux)
本文章主要记录Qt在linux电脑上调用so库的三种调用方式 方式一:静态加载so库 方式二:动态加载so库(QLibrary) 方式三:动态加载so库(dlopen) 其他: 封装的so库叫做: ...
- mysql交集查询按照时间范围查询myBatis
查询 开始时间 --结束时间 <if test="searchParam.startTime != null and searchParam.endTime != null" ...
- Windows系统编译libhv带SSL,开启WITH_OPENSSL
需要开发一个https的服务,使用libhv来做,需要重新编译libhv,需要开启 WITH_OPENSSL,前面编译一直很顺利,但是打开VS生成动态库的时候,报错,找不到ssl相关的文件,看了官方的 ...
- triple loss
Triplet Loss是深度学习中的一种损失函数,用于训练差异性较小的样本,如人脸等, Feed数据包括锚(Anchor)示例.正(Positive)示例.负(Negative)示例,通过优化锚示例 ...
- Android 开发入门(2)
0x04 简单控件 (1)文本显示 a. 添加文本 设置文本内容主要有两种方式: XML:通过属性android:text设置 在 layout 目录下新建 activity_text_view.xm ...