首页 > 其他分享 >Go语言学习之-带分割符的文件转excel-PLUS版

Go语言学习之-带分割符的文件转excel-PLUS版

时间:2023-12-15 11:00:10浏览次数:32  
标签:rowno log err excel len PLUS Printf Go colcnt

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文件为日志文件,可以查看相应日志 

标签:rowno,log,err,excel,len,PLUS,Printf,Go,colcnt
From: https://www.cnblogs.com/silencemaker/p/17902912.html

相关文章

  • 重磅:谷歌发布最强大AI模型【Google Gemini】
    https://www.cnblogs.com/eryueren/p/17901497.html一、前言北京时间2023年12月13日Google发布了最新的GeminiPro模型,并且提供了API访问。一个更好的消息是:GeminiPro可免费使用。赶紧体验起来吧~二、关于GoogleGemini是一款由GoogleAI开发的大型语言模型聊天机......
  • Argo Rollouts BlueGreen 配置
    ArgoRolloutsBlueGreen更新过程1.从稳定状态开始,activeService和PreviewService都指向revision1的ReplicaSet。2.用户通过修改Pod模板(spec.template.spec)来发起更新。3.创建的ReplicaSet的revision2的大小为0。4.PreviewService被修改为指向revision2的Re......
  • go-zero目录结构和说明
    .├──code-of-conduct.md行为准则├──CONTRIBUTING.md贡献指南├──core框架的核心组件│├──bloom布隆过滤器,用于检测一个元素是否在一个集合中│├──breaker熔断器,用于防止过多的请求......
  • 快速探索 Tetragon:基于 eBPF 的安全可观察性和执行工具
    Tetragon是一种灵活的安全可观察性和运行时策略执行工具,可直接使用eBPF应用策略和过滤,从而减少了监控、进程跟踪以及实时执行策略的开销。Tetragon提供了如下功能:监控进程执行监控文件操作监控网络活动执行策略最后一个侧重策略的执行,可以通过发送信号或覆盖系统调用......
  • 12月12日记录mybatis plus的初始学习
    今天开始mybatisplus的初始学习,首先是学习mybatisplus的引入方式需要引入下面三段代码<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.3.1</version></dependency>......
  • google gemini api使用
    title:googlegeminiapi使用banner_img:https://cdn.studyinglover.com/pic/2023/12/334c0c129076533308cbc7e03f8c55be.pngdate:2023-12-1423:15:00tags:-googlegeminigooglegeminiapi使用google最近发布了geminiapi,我之前在我的博客介绍了如何申请,这篇文章来......
  • ExcelVba 单元格历史记录(记录单元格变更历史)
    PublicTrackChangesAsBooleanSubToggleCellHistory()TrackChanges=NotTrackChangesIfTrackChangesThenMsgBox"单元格历史记录功能已开启。"ElseMsgBox"单元格历史记录功能已关闭。"EndIfEndSubPrivateSubWorkbook_She......
  • google gemini api申请
    title:googlegeminiapi申请banner_img:https://cdn.studyinglover.com/pic/2023/12/334c0c129076533308cbc7e03f8c55be.pngdate:2023-12-1422:40:00tags:-踩坑googlegeminiapi申请首先登陆https://ai.google.dev/pricing往下滑,看一看到免费选项,每分钟60词请求......
  • Excel--图表类型设置
    1.直线图框选包括标题的表格数据-插入-图表区-(推荐的图表-所有图表-柱形图)-即可生成图表(1)点击生成图表中的数据列-右键鼠标-设置坐标轴格式(右侧会生成相应菜单栏)其功能有:选择坐标轴选项(最后那个子菜单)-可设置坐标轴的范围、修改主要单位及次要单位、修改刻度线(2)单击条形图的长......
  • go上下文神器
    10Context:你必须掌握的多线程并发控制神器原创 码梦之旅 码梦之旅 2023-12-0223:11 发表于广东在上一节课中我留了一个作业,也就是让你自己练习使用sync.Map,相信你已经做出来了。现在我为你讲解sync.Map的方法。Store:存储一对key-value值。Load:根据key......