Go语言学习之-带分割符的文件转excel-PLUS版
package main
import (
"bufio"
"errors"
"flag"
"fmt"
"github.com/axgle/mahonia"
"github.com/xuri/excelize/v2"
"log"
"os"
"path"
"path/filepath"
"sort"
"strconv"
"strings"
)
var splitor = ""
var charset = "GBK"
func splt(c rune) bool {
//c = ''
if c == rune(splitor[0]) {
return true
} else {
return false
}
}
func ToAlphaString(value int) string {
if value < 0 {
return ""
}
var ans string
i := value + 1
for i > 0 {
ans = string((i-1)%26+65) + ans
i = (i - 1) / 26
}
return ans
}
//列表去重
func uniqvalue(vallist []string) (ret []string){
sort.Strings(vallist)
vlen:=len(vallist)
for i := 0; i < vlen; i++ {
if(i>0 && vallist[i-1]==vallist[i])||len(vallist[i])==0{
continue
}
ret=append(ret,vallist[i])
}
return ret
}
func list2sortdig(fldlistidx []string) []int {
//flds:=strings.Split(fldlistidx,",")
flds1:=make([]int, len(fldlistidx))
for i, fld := range fldlistidx {
if fv,err:=strconv.ParseInt(fld,10,8);err==nil{
flds1[i]= int(fv)
}
}
sort.Ints(flds1)
return flds1
}
func main() {
var enc mahonia.Decoder
//filename := "C:\\Users\\Downloads\\11.del"
//filename = "C:\\soft1\\11.txt"
var filename string
var headfile string
var hsplitor = "|"
var fldidxlist string
var top=-1
if len(os.Args) > 1 {
flag.ErrHelp = errors.New("")
flag.StringVar(&filename, "f", "111.dat", "--filename 文件名【可以把文件拖放在此处】")
flag.StringVar(&splitor, "sp", "\u0003", "--splitor [, \u0008 ,\u0003, \u0009 ] 分割符,一般为\u0003或者逗号等可见字符单字符")
flag.StringVar(&headfile, "hf", "111_head.txt", "--headfile 表头文件名【可以把文件拖放在此处,默认以|做分割符】,可以自定义")
flag.StringVar(&hsplitor, "hs", "|", "--hsplitor [, \u0008 ,\u0003, \u0009 ] 分割符,一般为\u0003或者逗号等可见字符单字符")
flag.StringVar(&charset, "c", "GBK", "--charset [,GBK/UTF-8... ] 字符集编码,一般为GBK")
flag.StringVar(&fldidxlist, "fdlst", "1", "--字段列表编号,用英文逗号分割,最后用双引号引用,如1,2,3,4,第一列编号为1")
flag.IntVar(&top, "t", -1, "--top 取前多少个")
flag.Parse()
//rune(splitor)
fmt.Println("filename:" + filename)
//fmt.Println([]rune(splitor))
fmt.Printf("%s,%X", "splitor:"+string(splitor)+",hex:", splitor)
//return
} else {
fmt.Println("请输入文件名,可以直接用鼠标点击文件拖入到此(如果有表头文件,请确保同目录下的文件名以_head.txt结束,如1.dat,头文件名为1_head.txt):")
fmt.Scan(&filename)
}
enc = mahonia.NewDecoder(charset)
if len(filename) < 5 {
tmpstr := fmt.Sprintf("输入的文件名[%s]长度好像不够5位,是否有问题?", filename)
panic(errors.New(tmpstr))
}
paths, basefile := filepath.Split(filename)
filesuffix := path.Ext(basefile)
newbasename := paths + basefile[0:len(basefile)-len(filesuffix)]
headname:=newbasename+"_head.txt"
xlsfilename := newbasename + ".xlsx"
logfilename := newbasename + ".log"
logFile, err := os.OpenFile(logfilename, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
if err != nil {
fmt.Println("open log file failed, err:", err)
return
}
log.SetOutput(logFile)
log.SetFlags(log.Lshortfile | log.Lmicroseconds | log.Ldate)
log.Printf("日志文件:[%s]\n", logfilename)
log.Printf("目标文件[%s]\n", xlsfilename)
fmt.Printf("目标文件路径为:[%s]\n", xlsfilename)
fmt.Printf("目标日志路径为:[%s]\n", logfilename)
fp1, err := os.Open(filename)
if err != nil {
tmpstr := fmt.Sprintf("%s文件打开错误!", filename)
log.Println(tmpstr)
panic(err)
}
defer fp1.Close()
row0 := make([]string, 10,300)
var headname0=""
_,err=os.Stat(headname)
if err==nil{
headname0=headname
log.Printf("-----输入的头文件[%s]存在------,以此为解析!\n", headname)
}
_, err = os.Stat(headfile)
if err==nil{
headname0=headfile
log.Printf("-----输入的头文件[%s]存在------,以此为解析!\n", headfile)
}
if len(headname0)==0{
log.Printf("-----输入的头文件不存在------!\n")
}
fp2, err := os.Open(headname0)
if err != nil {
tmpstr := fmt.Sprintf("%s文件打开错误!", headname0)
log.Println(tmpstr)
}else{
log.Printf("-----读取%s------!\n",headname0)
fs2:=bufio.NewScanner(fp2)
fs2.Scan()
splitstrLine:=fs2.Text()
row0= strings.Split(splitstrLine, hsplitor)
tmpstr:="{"
for i, rval := range row0 {
tmpstr+=strconv.Itoa(i+1)+":"+enc.ConvertString(rval)+","
}
tmpstr+=tmpstr+"}"
log.Printf("-----读取字段%d个,第一个是[%s]------!\n", len(row0),tmpstr)
}
defer fp2.Close()
fs := bufio.NewScanner(fp1)
//fs1 := bufio.NewScanner(fp2)
var rowno = 2
if len(row0)>1{
rowno = 1
}
log.Printf("-----rowno:%d------!\n", rowno)
//xlsfilename := "1122221.xlsx"
f := excelize.NewFile()
f.SaveAs(xlsfilename)
file1, err := excelize.OpenFile(xlsfilename)
if err != nil {
log.Println(err)
}
streamWriter, err := file1.NewStreamWriter(enc.ConvertString("Sheet1"))
if err != nil {
log.Println(err)
}
defer func() {
if err := recover(); err != nil {
streamWriter.Flush()
f.SaveAs(xlsfilename)
file1.Save()
log.Printf("recover:%v", err)
}
}()
f.SetActiveSheet(1)
//f.SetSheetName("Sheet1")
//f.SetPanes("Sheet1",`{"freeze":true,"split":false,"x_split":0,"y_split":1,"top_left_cell":"A2","actve_pane":"topRight"}`)
streamWriter.SetPanes( &excelize.Panes{
Freeze: true,
Split: false,
XSplit: 0,
YSplit: 1,
TopLeftCell: "A2",
ActivePane: "bottomLeft",
Selection: []excelize.Selection{
{ ActiveCell: "A2", Pane: "bottomLeft"},
},
})
//defer f.SaveAs(xlsfilename)
//index:=f.NewSheet("data")
//f.SetActiveSheet(index)
fldidxlist1:=list2sortdig(uniqvalue(strings.Split(fldidxlist,hsplitor)))
colcnt:=0
for fs.Scan() {
splitstrLine := fs.Text()
//fildstr := strings.FieldsFunc(splitstrLine, splt)
fildstr := strings.Split(splitstrLine, splitor)
//log.Printf("fldidxlist1:[%d] fildstr:[%s]", len(fldidxlist1),fildstr)
if len(fldidxlist1)>1 {
colcnt=len(fldidxlist1)
}else{
colcnt = len(fildstr)
}
//log.Printf("pos:%d-->colcnt:[%d]\n",rowno,colcnt)
//row := make([]interface{}, colcnt)
row := make([]interface{}, colcnt)
if rowno==1 {
log.Printf("recover:%v", fldidxlist1)
if len(fldidxlist1)>1{
colcnt=len(fldidxlist1)
for i := 0; i < colcnt; i++ {
row[i]=enc.ConvertString(row0[fldidxlist1[i]-1])
}
}else if(len(row0)>1){
//需要用此语法处理
for i := 0; i < len(row0) && row0[i]!=""; i++ {
row[i]=enc.ConvertString(row0[i])
}
}
//log.Printf("-----[%d]第一个是[%s],rowno[%d]------!\n",colcnt,row[:colcnt],rowno)
cell, _ := excelize.CoordinatesToCellName(1, rowno)
//log.Printf("----1-")
if err := streamWriter.SetRow(cell, row[:colcnt]); err != nil {
log.Println(err)
}
//log.Printf("-----")
row = make([]interface{}, len(row))
//log.Printf("-----2")
if top>0{
top++
}
//log.Printf("top:[%d] ",top)
rowno++
}
//log.Printf("colcnt:[%d] ",colcnt)
//row = make([]interface{}, colcnt)
for colno := 0; colno < colcnt; colno++ {
tmpcolno:=colno
if len(fldidxlist1)>1{
tmpcolno=fldidxlist1[colno]-1
}
//log.Printf("tmpcolno:[%d] ",tmpcolno)
if fildstr[tmpcolno] != "" {
row[colno] = enc.ConvertString(fildstr[tmpcolno])
} else {
row[colno] = ""
}
}
//log.Println("for over ")
cell, _ := excelize.CoordinatesToCellName(1, rowno)
if err := streamWriter.SetRow(cell, row[:colcnt]); err != nil {
log.Println(err)
}
if rowno%30000 == 0 {
log.Printf("-----已写入[%d]行------\n", rowno)
}
if rowno > excelize.TotalRows {
panic(errors.New("rows number exceeds maximum limit"))
}
//if rowno >= 20000 {
// break
//}
if top>0 && rowno>=top{
log.Printf("-----已写入[%d]行------\n", rowno)
break
}
rowno++
}
if len(row0)>1{
rowno--
}
log.Printf("-----共写入数据[%d]行------\n", rowno)
if err := streamWriter.Flush(); err != nil {
log.Println(err)
//return
}
if err := file1.Save(); err != nil {
log.Println(err)
}
//println(fp1)
log.Println("完成!")
os.Exit(0)
}
操作步骤
附件中的exe文件是可执行文件,
在wps中需要另存为一个目录,再使用
在word中可以复制,粘贴到一个目录再使用
此程序的作用是把原来的dat文件(带分割符的文件即可,数据文件的后缀名可以是其他,如txt)转换成excel的后缀名为xlsx的文件
可以用于大量的数据的转换
1、双击操作(全表转换)
双击Dat2Xls.exe,拖入程序
如果需要表头,请把表头的名字修改为 _head.txt结尾的文件名
如您要转换的文件为1.dat 表头则为 1_head.txt
回车即可
2、命令行操作(涉及到高级操作,自定义选择选项)
直接在命令行拖入此程序,可以查看有哪些选项
注意:
只有文件是必须有的
运行如图:

帮助如图:

字符编码一般都是GBK,即需要转换的文件和表头文件都是一个编码格式
cmd下切换到Dat2Xls.exe的程序所在目录运行
如下命令:
简写为: -f后跟的是需要转换为excel的文件名
Dat2Xls.exe -f E:\myexe\a20210831.dat -fdlst "1|2|3|4|5|6|7|20|30"
解析:f后面为需要解析的文件名,拖入即可显示全文件名,fdlst后面为数据所在列的编号,需要用双引号引起来,中间的列号用|分割,列号从1开始,至少为两列
如果不需要指定列,则不需要-fdlst参数
Dat2Xls.exe -f E:\myexe\a_20210831.dat
3、查看日志
解析目录下会有一个同名的.log文件为日志文件,可以查看相应日志

浙公网安备 33010602011771号