导出csv方案优化

网友投稿 876 2022-05-30

简介

上一篇文章,笔者使用excel的一篇入门文章,在本文笔者将会继续上一篇深入研究一下相关优化方案。

实验数据,191944行记录,csv文件总大小58m。

执行方案

不优化

直接全部读出然后导出:

代码

package main import ( "encoding/csv" "fmt" "log" "os" "time" ) var tFmt = "2006-01-02 15:04:05" func main() { content := readFile() fmt.Printf("%s - read file end......%d\n",time.Now().Format(tFmt),len(content)) exportFile(content) } func readFile() [][]string { //准备读取文件 fileName := "RPT_NORMAL_D_共享审批效率.csv" fmt.Printf("%s - read file......\n",time.Now().Format(tFmt)) fs1, _ := os.Open(fileName) r1 := csv.NewReader(fs1) content, err := r1.ReadAll() if err != nil { log.Fatalf("can not readall, err is %+v", err) } return content } func exportFile(content [][]string) { fmt.Printf("%s - start export file......\n",time.Now().Format(tFmt)) // 1. 导出头到文件1 f, err := os.Create("test.csv") if err != nil { panic(err) } defer f.Close() f.WriteString("\xEF\xBB\xBF")// 写入UTF-8 BOM w := csv.NewWriter(f) //data := content[:1] w.WriteAll(content) w.Flush() fmt.Printf("%s - end export file......\n",time.Now().Format(tFmt)) }

测试日志,如下可以看出导出时间1秒内可以完成 :

# 数据整包一次导出 2021-07-24 15:30:28 - read file...... 2021-07-24 15:30:28 - read file end......191944 2021-07-24 15:30:28 - start export file...... 2021-07-24 15:30:28 - end export file......

时间优化

开几个线程并发的写文件,然后调用命令合并文件

执行脚本

go run main.go echo $(date )" - start merge file" cat temp1.csv temp2.csv temp3.csv temp4.csv> test.csv echo $(date )" - end merge file"

执行代码

package main import ( "encoding/csv" "fmt" "log" "os" "strconv" "time" ) var tFmt = "2006-01-02 15:04:05" func main() { content := readFile() fmt.Printf("%s - read file end......%d\n",time.Now().Format(tFmt),len(content)) exportFile(content) time.Sleep(time.Millisecond*200) } func readFile() [][]string { //准备读取文件 fileName := "RPT_NORMAL_D_共享审批效率.csv" fmt.Printf("%s - read file......\n",time.Now().Format(tFmt)) fs1, _ := os.Open(fileName) r1 := csv.NewReader(fs1) content, err := r1.ReadAll() if err != nil { log.Fatalf("can not readall, err is %+v", err) } return content } func exportFile(content [][]string) { fmt.Printf("%s - start export multiple file......\n",time.Now().Format(tFmt)) length := len(content) // 1. 导出头到文件1 f, err := os.Create("test.csv") if err != nil { panic(err) } defer f.Close() f.WriteString("\xEF\xBB\xBF")// 写入UTF-8 BOM w := csv.NewWriter(f) data := content[:1] w.WriteAll(data) // 2. 并发循环导出,一次100,000 (10万数据) 到 1个文件,最终输出n个10万数据的文件 count := 1 pos :=1 for pos < length { maxPos := pos+50000 if maxPos > length { maxPos = length } temp := content[pos: maxPos ] go wiriteTempFile(pos,"temp"+strconv.Itoa(count)+".csv",temp) count++ pos += 50000 } // 3. 合并n个文件到文件1 w.Flush() //fmt.Printf("%s - export file success......\n",time.Now().Format(tFmt)) } func wiriteTempFile(pos int,file string,data [][] string) { fmt.Printf("len === %d , pos=%d \n",len(data),pos) f, err := os.Create(file) if err != nil { panic(err) } defer f.Close() //f.WriteString("\xEF\xBB\xBF") // 写入UTF-8 BOM w := csv.NewWriter(f) w.WriteAll(data) w.Flush() }

# 启动4个线程并发导出4个文件,然后调用命令合并文件 $ sh merge.sh 2021-07-24 16:30:06 - read file...... 2021-07-24 16:30:07 - read file end......191944 2021-07-24 16:30:07 - start export multiple file...... len === 50000 , pos=1 len === 50000 , pos=50001 len === 41943 , pos=150001 len === 50000 , pos=100001 Sat Jul 24 16:30:07 2021 - start merge file Sat Jul 24 16:30:08 2021 - end merge file

导出csv方案优化

结论

50m级别,不管是多线程导出还是单线程全部导出处理对时间影响不明显

在实际生产总,可以根据具体情况选择解决方案:

1、源数据一次读出,一次写入文件导出,无限制条件

2、源数据分批读出,分批写入文件,优化内存和CPU,牺牲速度,增对超大文件,不放使用该方案设计离线导出

3、源数据分批多线程读出,分批多线程写入不同文件,合并文件,牺牲内存和CPU,争取速度(文件不大情况下可能时间更慢)

空了尝试一下G级别的文件,使用方法3的效果。

任务调度

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Java JDK 10:下一代 Java 有哪些新特性?
下一篇:华为云FusionInsight湖仓一体,加速金融行业数字化转型升级
相关文章