forked from go/golangs_learn
VIVIMAN
3 years ago
5 changed files with 110 additions and 3 deletions
@ -0,0 +1,77 @@ |
|||||
|
package main |
||||
|
|
||||
|
/** |
||||
|
* 推荐:使用方式,写的输出excel文件 |
||||
|
**/ |
||||
|
import ( |
||||
|
// "github.com/360EntSecGroup-Skylar/excelize/v2"
|
||||
|
"github.com/360EntSecGroup-Skylar/excelize" |
||||
|
"strconv" |
||||
|
) |
||||
|
|
||||
|
func main() { |
||||
|
|
||||
|
} |
||||
|
|
||||
|
// maxCharCount 最多26个字符A-Z
|
||||
|
const maxCharCount = 26 |
||||
|
|
||||
|
// ExportExcel 导出Excel文件
|
||||
|
// sheetName 工作表名称, 注意这里不要取sheet1这种名字,否则导致文件打开时发生部分错误。
|
||||
|
// headers 列名切片, 表头
|
||||
|
// rows 数据切片,是一个二维数组
|
||||
|
func ExportExcel(sheetName string, headers []string, rows [][]interface{}) (*excelize.File, error) { |
||||
|
f := excelize.NewFile() |
||||
|
sheetIndex := f.NewSheet(sheetName) |
||||
|
maxColumnRowNameLen := 1 + len(strconv.Itoa(len(rows))) |
||||
|
columnCount := len(headers) |
||||
|
if columnCount > maxCharCount { |
||||
|
maxColumnRowNameLen++ |
||||
|
} else if columnCount > maxCharCount*maxCharCount { |
||||
|
maxColumnRowNameLen += 2 |
||||
|
} |
||||
|
columnNames := make([][]byte, 0, columnCount) |
||||
|
for i, header := range headers { |
||||
|
columnName := getColumnName(i, maxColumnRowNameLen) |
||||
|
columnNames = append(columnNames, columnName) |
||||
|
// 初始化excel表头,这里的index从1开始要注意
|
||||
|
curColumnName := getColumnRowName(columnName, 1) |
||||
|
f.SetCellValue(sheetName, curColumnName, header) |
||||
|
} |
||||
|
for rowIndex, row := range rows { |
||||
|
for columnIndex, columnName := range columnNames { |
||||
|
// 从第二行开始
|
||||
|
f.SetCellValue(sheetName, getColumnRowName(columnName, rowIndex+2), row[columnIndex]) |
||||
|
} |
||||
|
} |
||||
|
f.SetActiveSheet(sheetIndex) |
||||
|
return f, nil |
||||
|
} |
||||
|
|
||||
|
// getColumnName 生成列名
|
||||
|
// Excel的列名规则是从A-Z往后排;超过Z以后用两个字母表示,比如AA,AB,AC;两个字母不够以后用三个字母表示,比如AAA,AAB,AAC
|
||||
|
// 这里做数字到列名的映射:0 -> A, 1 -> B, 2 -> C
|
||||
|
// maxColumnRowNameLen 表示名称框的最大长度,假设数据是10行,1000列,则最后一个名称框是J1000(如果有表头,则是J1001),是4位
|
||||
|
// 这里根据 maxColumnRowNameLen 生成切片,后面生成名称框的时候可以复用这个切片,而无需扩容
|
||||
|
func getColumnName(column, maxColumnRowNameLen int) []byte { |
||||
|
const A = 'A' |
||||
|
if column < maxCharCount { |
||||
|
// 第一次就分配好切片的容量
|
||||
|
slice := make([]byte, 0, maxColumnRowNameLen) |
||||
|
return append(slice, byte(A+column)) |
||||
|
} else { |
||||
|
// 递归生成类似AA,AB,AAA,AAB这种形式的列名
|
||||
|
return append(getColumnName(column/maxCharCount-1, maxColumnRowNameLen), byte(A+column%maxCharCount)) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// getColumnRowName 生成名称框
|
||||
|
// Excel的名称框是用A1,A2,B1,B2来表示的,这里需要传入前一步生成的列名切片,然后直接加上行索引来生成名称框,就无需每次分配内存
|
||||
|
func getColumnRowName(columnName []byte, rowIndex int) (columnRowName string) { |
||||
|
l := len(columnName) |
||||
|
columnName = strconv.AppendInt(columnName, int64(rowIndex), 10) |
||||
|
columnRowName = string(columnName) |
||||
|
// 将列名恢复回去
|
||||
|
columnName = columnName[:l] |
||||
|
return |
||||
|
} |
@ -0,0 +1,30 @@ |
|||||
|
package main |
||||
|
|
||||
|
import ( |
||||
|
"flag" |
||||
|
"fmt" |
||||
|
"log" |
||||
|
"os" |
||||
|
) |
||||
|
|
||||
|
var demoFile = `(示例)2022122235133.gz` |
||||
|
var demoPath = `(示例)D:/hzb2021` |
||||
|
|
||||
|
var fileName string |
||||
|
var pathName string |
||||
|
|
||||
|
func init() { |
||||
|
flag.CommandLine = flag.NewFlagSet("", flag.ExitOnError) |
||||
|
flag.CommandLine.Usage = func() { |
||||
|
fmt.Fprintf(os.Stderr, "Usage of %s:\n", "question") |
||||
|
flag.PrintDefaults() |
||||
|
} |
||||
|
flag.StringVar(&fileName, "f", demoFile, "选择 gz 格式的备份文件") |
||||
|
flag.StringVar(&pathName, "p", demoPath, "选择 安装应用 的目录信息") |
||||
|
} |
||||
|
|
||||
|
func main() { |
||||
|
flag.Parse() |
||||
|
log.Panicln(fileName) |
||||
|
log.Panicln(pathName) |
||||
|
} |
Loading…
Reference in new issue