需求:把下面的csv文件,自动写入到excel模版中,
1.自动按照csv的行数,以日期时间名问sheet名成写入到excel表的sheet名称中
2.自动复制excel的第一个sheet的所有内容,同时用csv文件的内容填充特定区域内容
xy1.csv文件
日期 最高温度 最低温度 天气 风力风向 空气质量
2023-01-01 周日 4° 0° 多云~阴 东北风1级 256 重度
2023-01-02 周一 6° -4° 多云~晴 东风1级 285 重度
2023-01-03 周二 7° -3° 多云~阴 东北风1级 296 重度
2023-01-04 周三 6° -2° 多云~阴 东风1级 361 严重
2023-01-05 周四 8° -2° 多云~晴 东南风1级 368 严重
2023-01-06 周五 14° -2° 晴 西南风2级 174 中度
2023-01-07 周六 14° -2° 晴 东北风1级 163 中度
2023-01-08 周日 12° -3° 晴 东风1级 224 重度
xx.xlsx文件[模版文件],需要依托这个excel模版进行复制N个sheet表格,把上面的csv文件填充进去
=================
不同版本,不同方式测试,建议参看结构体方式
一、问题版本
解决的难题,
1.解决读取中文乱码的问题;
2.自动化事项
读取csv文件到excel文件中,批量自动化设置
待解决的问题,文件名称的时间与表里时间不一致的问题
package main
import (
"bytes"
"encoding/csv"
"fmt"
"github.com/xuri/excelize/v2"
"golang.org/x/text/encoding/simplifiedchinese"
"golang.org/x/text/transform"
"io"
"io/ioutil"
"strings"
)
// 生成表格数据
func creatxlsx(lists [][]string) {
//f, err := excelize.OpenFile("施工日志模版.xlsx", excelize.Options{Password: "password"})
f, err := excelize.OpenFile("施工日志模版.xlsx")
if err != nil {
return
}
for num, item := range lists {
year_xq := item[0]
year_xq_slices := strings.Split(year_xq, " ")
year := year_xq_slices[0]
//需要把2016-4-23修改年的格式为 2016年4月23日
year_lists := strings.Split(year, "-")
newyea := year_lists[0]
newmon := year_lists[1]
newday := year_lists[2]
newyear_fomat := fmt.Sprintf("%s年%s月%s日", newyea, newmon, newday)
xq := year_xq_slices[1]
//xq := year_xq_slices[1]
//=====================================
zg := item[1]
zd := item[2]
tq := item[3]
fengli := item[4]
//sheetname 201302
//fmt.Println("year===>", year)
index, err := f.NewSheet(year)
if err != nil {
fmt.Println(err)
return
}
err = f.CopySheet(num, index)
if err != nil {
return
}
//获取每个单元表
evesheet := f.GetSheetName(num)
f.SetCellValue(evesheet, "I7", tq)
f.SetCellValue(evesheet, "I8", fengli)
f.SetCellValue(evesheet, "I9", zg)
f.SetCellValue(evesheet, "I10", zd)
//表格中 年的位置 星期的位置
f.SetCellValue(evesheet, "P6", newyear_fomat)
f.SetCellValue(evesheet, "X6", xq)
//if err := f.SaveAs("Book1.xlsx"); err != nil {
// fmt.Println(err)
//}
}
if err := f.SaveAs("Book1.xlsx"); err != nil {
fmt.Println(err)
}
}
func readcsvline2() [][]string {
lists := make([][]string, 0)
//file, err := os.Open("xy1.csv")
file, err := ioutil.ReadFile("xy1.csv")
if err != nil {
fmt.Println(err)
}
//解决读取csv中文乱码的问题
reader := csv.NewReader(transform.NewReader(bytes.NewReader(file), simplifiedchinese.GBK.NewDecoder()))
reader.FieldsPerRecord = -1
// csvdata, err := reader.ReadAll()
for {
csvdata, err := reader.Read() // 按行读取数据,可控制读取部分
if err != nil && err != io.EOF {
fmt.Println("Error:", err)
break
}
if err == io.EOF {
break
}
lists = append(lists, csvdata)
//fmt.Println(csvdata)
}
//去掉csv文件头的那行
return lists[1:]
}
func main() {
lists := readcsvline2()
creatxlsx(lists)
}
代码与python项目相似:
https://ht666666.blog.csdn.net/article/details/130973792?spm=1001.2014.3001.5502
二、修正版本
修正版本:
下面的版本完全可以使用了
可以使用了
package main
import (
"bytes"
"encoding/csv"
"fmt"
excelize "github.com/xuri/excelize/v2"
"golang.org/x/text/encoding/simplifiedchinese"
"golang.org/x/text/transform"
"io"
"io/ioutil"
"strings"
)
// 生成表格数据
func creatxlsx(lists [][]string) {
//f, err := excelize.OpenFile("施工日志模版.xlsx", excelize.Options{Password: "password"})
f, err := excelize.OpenFile("施工日志魔板.xlsx")
if err != nil {
return
}
for num, item := range lists {
year_xq := item[0]
year_xq_slices := strings.Split(year_xq, " ")
year := year_xq_slices[0]
//需要把2016-4-23修改年的格式为 2016年4月23日
year_lists := strings.Split(year, "-")
newyea := year_lists[0]
newmon := year_lists[1]
newday := year_lists[2]
newyear_fomat := fmt.Sprintf("%s年%s月%s日", newyea, newmon, newday)
xq := year_xq_slices[1]
//xq := year_xq_slices[1]
//=====================================
zg := item[1]
zd := item[2]
tq := item[3]
fengli := item[4]
//sheetname 201302
//fmt.Println("year===>", year)
index, err := f.NewSheet(year)
if err != nil {
fmt.Println(err)
return
}
err = f.CopySheet(num, index)
if err != nil {
return
}
//获取每个单元表
evesheet := f.GetSheetName(index)
//evesheet := f.GetSheetName(num) //错误的地方,应该是上面的index
f.SetCellValue(evesheet, "I7", tq)
f.SetCellValue(evesheet, "I8", fengli)
f.SetCellValue(evesheet, "I9", zg)
f.SetCellValue(evesheet, "I10", zd)
//表格中 年的位置 星期的位置
f.SetCellValue(evesheet, "P6", newyear_fomat)
f.SetCellValue(evesheet, "X6", xq)
//if err := f.SaveAs("Book1.xlsx"); err != nil {
// fmt.Println(err)
//}
}
if err := f.SaveAs("Book1.xlsx"); err != nil {
fmt.Println(err)
}
}
func readcsvline2() [][]string {
lists := make([][]string, 0)
//file, err := os.Open("xy1.csv")
file, err := ioutil.ReadFile("xy1.csv")
if err != nil {
fmt.Println(err)
}
//解决读取csv中文乱码的问题
reader := csv.NewReader(transform.NewReader(bytes.NewReader(file), simplifiedchinese.GBK.NewDecoder()))
reader.FieldsPerRecord = -1
// csvdata, err := reader.ReadAll()
for {
csvdata, err := reader.Read() // 按行读取数据,可控制读取部分
if err != nil && err != io.EOF {
fmt.Println("Error:", err)
break
}
if err == io.EOF {
break
}
lists = append(lists, csvdata)
//fmt.Println(csvdata)
}
//去掉csv文件头的那行
return lists[1:]
}
func main() {
lists := readcsvline2()
creatxlsx(lists)
}
修正的地方 :
三、优化版本【可以使用了--推荐】
package main
import (
"bytes"
"encoding/csv"
"fmt"
"github.com/xuri/excelize/v2"
"golang.org/x/text/encoding/simplifiedchinese"
"golang.org/x/text/transform"
"io"
"io/ioutil"
"strings"
)
// 生成表格数据
func creatxlsx(lists [][]string) {
//f, err := excelize.OpenFile("施工日志模版.xlsx", excelize.Options{Password: "password"})
f, err := excelize.OpenFile("conf/施工日志模版.xlsx")
if err != nil {
return
}
for _, item := range lists {
year_xq := item[0]
year_xq_slices := strings.Split(year_xq, " ")
//2016-4-23
year := year_xq_slices[0]
// 星期三
xq := year_xq_slices[1]
//==================================
//需要把2016-4-23修改年的格式为 2016年4月23日
year_lists := strings.Split(year, "-")
newyea := year_lists[0]
newmon := year_lists[1]
newday := year_lists[2]
newyear_fomat := fmt.Sprintf("%s年%s月%s日", newyea, newmon, newday)
//xq := year_xq_slices[1]
//=====================================
//最高温度,最低温度,天气,风力
zg := item[1]
zd := item[2]
tq := item[3]
fengli := item[4]
//sheetname 201302
//fmt.Println("year===>", year)
//创建sheet表的名称为 2016-4-23 的表名
index, err := f.NewSheet(year)
if err != nil {
fmt.Println(err)
return
}
//复制序列号 0 的索引[需要的模版]到新的索引的位置
err = f.CopySheet(0, index)
//err = f.CopySheet(num, index)
if err != nil {
return
}
//获取每个单元表,获取新建sheet表的index,在这里获取每个单元格的sheet
evesheet := f.GetSheetName(index)
//设置单元格的值
f.SetCellValue(evesheet, "I7", tq)
f.SetCellValue(evesheet, "I8", fengli)
f.SetCellValue(evesheet, "I9", zg)
f.SetCellValue(evesheet, "I10", zd)
//表格中 年的位置 星期的位置
f.SetCellValue(evesheet, "P6", newyear_fomat)
f.SetCellValue(evesheet, "X6", xq)
//if err := f.SaveAs("Book1.xlsx"); err != nil {
// fmt.Println(err)
//}
}
if err := f.SaveAs("Book1.xlsx"); err != nil {
fmt.Println(err)
}
fmt.Println("数据处理完毕。")
}
func readcsvline2(csvname string) [][]string {
lists := make([][]string, 0)
//file, err := os.Open("xy1.csv")
//打开csv文件的内容
file, err := ioutil.ReadFile(csvname)
//file, err := ioutil.ReadFile("xy1.csv")
if err != nil {
fmt.Println(err)
}
//解决读取csv中文乱码的问题
reader := csv.NewReader(transform.NewReader(bytes.NewReader(file), simplifiedchinese.GBK.NewDecoder()))
reader.FieldsPerRecord = -1
// csvdata, err := reader.ReadAll()
for {
csvdata, err := reader.Read() // 按行读取数据,可控制读取部分
if err != nil && err != io.EOF {
fmt.Println("Error:", err)
break
}
if err == io.EOF {
break
}
lists = append(lists, csvdata)
//fmt.Println(csvdata)
}
//去掉csv文件头的那行
return lists[1:]
}
func main() {
for {
var csvname string
fmt.Println("请输入城市的天气csv表名称[q :退出]:")
fmt.Scan(&csvname)
if !strings.HasSuffix(csvname, ".csv") {
fmt.Println("输入文件后缀错误,必须是*.CSV文件")
break
}
//判断输出的是Q 还是 q ,都是通过字符串转换后都是小写进行判断
newcsvnamne := strings.ToLower(csvname)
if newcsvnamne == "q" {
break
}
lists := readcsvline2(csvname)
creatxlsx(lists)
}
}
四、针对上面的代码优化,采用结构体方式进行重构,代码大部分重写【结构体方式】
采用结构体方式:重构了一下代码;
package main
import (
"bytes"
"encoding/csv"
"fmt"
"github.com/xuri/excelize/v2"
"golang.org/x/text/encoding/simplifiedchinese"
"golang.org/x/text/transform"
"io"
"io/ioutil"
"strings"
"time"
)
// 定义读取的csv文件的字段信息
type Csvfield struct {
Yead_week string
Zg string
Zd string
Tq string
Fengli string
Zhiliang string
}
// 生成表格数据,升级版本,对应readcsvline2Dic的未文件
func creatxlsxU1(lists []Csvfield) {
//f, err := excelize.OpenFile("施工日志模版.xlsx", excelize.Options{Password: "password"})
f, err := excelize.OpenFile("conf/施工日志模版.xlsx")
if err != nil {
return
}
for _, item := range lists {
year_xq := item.Yead_week
year_xq_slices := strings.Split(year_xq, " ")
//2016-4-23
year := year_xq_slices[0]
// 星期三
xq := year_xq_slices[1]
//==================================
//需要把2016-4-23修改年的格式为 2016年4月23日
year_lists := strings.Split(year, "-")
newyea := year_lists[0]
newmon := year_lists[1]
newday := year_lists[2]
newyear_fomat := fmt.Sprintf("%s年%s月%s日", newyea, newmon, newday)
//xq := year_xq_slices[1]
//=====================================
//最高温度,最低温度,天气,风力
zg := item.Zg
zd := item.Zd
tq := item.Tq
fengli := item.Fengli
//sheetname 201302
//fmt.Println("year===>", year)
//创建sheet表的名称为 2016-4-23 的表名
index, err := f.NewSheet(year)
if err != nil {
fmt.Println(err)
return
}
//复制序列号 0 的索引[需要的模版]到新的索引的位置
err = f.CopySheet(0, index)
//err = f.CopySheet(num, index)
if err != nil {
return
}
//获取每个单元表,获取新建sheet表的index,在这里获取每个单元格的sheet
evesheet := f.GetSheetName(index)
//设置单元格的值
f.SetCellValue(evesheet, "I7", tq)
f.SetCellValue(evesheet, "I8", fengli)
f.SetCellValue(evesheet, "I9", zg)
f.SetCellValue(evesheet, "I10", zd)
//表格中 年的位置 星期的位置
f.SetCellValue(evesheet, "P6", newyear_fomat)
f.SetCellValue(evesheet, "X6", xq)
}
//文件名的组成方式target_36.xlsx文件名
inttime := time.Now().Second()
timestr := fmt.Sprintf("%02d", inttime)
saveExcelname := "target_" + timestr + ".xlsx"
if err := f.SaveAs(saveExcelname); err != nil {
fmt.Println(err)
}
fmt.Println("数据处理完毕。")
}
// 返回[]Csvfield 方式 ,升级版本,以结构体方式进行
func readcsvline2Dic(csvname string) []Csvfield {
lists := make([]Csvfield, 0)
//file, err := os.Open("xy1.csv")
//打开csv文件的内容
file, err := ioutil.ReadFile(csvname)
//file, err := ioutil.ReadFile("xy1.csv")
if err != nil {
fmt.Println(err)
}
//解决读取csv中文乱码的问题
reader := csv.NewReader(transform.NewReader(bytes.NewReader(file), simplifiedchinese.GBK.NewDecoder()))
reader.FieldsPerRecord = -1
// csvdata, err := reader.ReadAll()
for {
csvdata, err := reader.Read() // 按行读取数据,可控制读取部分
if err != nil && err != io.EOF {
fmt.Println("Error:", err)
break
}
if err == io.EOF {
break
}
//数据组装到结构体中
stc1 := Csvfield{Yead_week: csvdata[0],
Zg: csvdata[1],
Zd: csvdata[2],
Tq: csvdata[3],
Fengli: csvdata[4],
Zhiliang: csvdata[5],
}
lists = append(lists, stc1)
//fmt.Println(csvdata)
}
//跳过csv首行 字段头部分
return lists[1:]
}
// 测试代码
func creatxlsxU2(lists []Csvfield) {
for i, item := range lists {
//fmt.Println(i, "====>", item)xy5
fmt.Printf("%T%T", i, item)
fmt.Println(item.Yead_week)
}
}
func main() {
//struct版本---->新的内容
for {
var csvname string
fmt.Println("请输入城市的天气csv表名称[q :退出]:")
fmt.Scan(&csvname)
if !strings.HasSuffix(csvname, ".csv") {
fmt.Println("输入文件后缀错误,必须是*.CSV文件")
break
}
//判断输出的是Q 还是 q ,都是通过字符串转换后都是小写进行判断
newcsvnamne := strings.ToLower(csvname)
if newcsvnamne == "q" {
break
}
lists := readcsvline2Dic(csvname)
//fmt.Println(lists)
creatxlsxU1(lists)
}
}
五、编译,参加我以前写的内容;
编译exe文件+图标的链接地址:
https://ht666666.blog.csdn.net/article/details/124512392
重点关注 :
如果打包命令不成功,需要安装mingw-w64这个软件【绿色版本解压即可使用】,关注我我的上个编译图标的链接
1.下载地址
https://sourceforge.net/projects/mingw-w64/
2.编译命令:
windres -o readcsvtoxlsxv2.1.syso readcsvtoxlsxv2.1.rc
windres -o 这个就是编译命令;
后面的两个
readcsvtoxlsxv2.1.syso 需要生成的文件[readcsvtoxlsxv2.1---》修改为你的程序名称]
readcsvtoxlsxv2.1.rc ;你的第一次生成的文件
总结:
编译的时候的文件名基本都是一样的 只是后缀不一样的!
编译局题目内容见
Go在Window平台下编译出来的exe如何添加一个图标--推荐使用_雨师@的博客-CSDN博客
https://ht666666.blog.csdn.net/article/details/124512392