go语言操作csv

go语言操作csv

简介

本文讲解如何使用go语言读csv,如何使用go语言写csv文件,最后讲解一个内容如何使用使用go语言快速导出一个包含20万条记录的csv文件。

详细步骤

写csv

  • 程序
package main

import (
	"encoding/csv"
	"os"
)

func main() {
	//创建csv文件
	f, err := os.Create("test.csv")
	if err != nil {
		panic(err)
	}
	//异步管理
	defer f.Close()
	// 写入UTF-8 BOM
	f.WriteString("\xEF\xBB\xBF")
	//创建一个新的写入文件流
	w := csv.NewWriter(f)
	data := [][]string{
		{"序号", "姓名", "年龄","月薪"},
		{"1", "小李", "23","2300"},
		{"2", "小张", "23","2500"},
		{"3", "小马", "23","5000"},
	}
	//写入数据
	w.WriteAll(data)
	w.Flush()
}

  • 执行程序(go run main.go),完成后写入的csv文件
序号,姓名,年龄,月薪
1,"小李,",23,2300
2,小张,23,2500
3,小马,23,5000

读csv

package main

import (
	"encoding/csv"
	"fmt"
	"io"
	"log"
	"os"
)

func main() {
	//准备读取文件
	fileName := "test.csv"
	fs, err := os.Open(fileName)
	if err != nil {
		log.Fatalf("can not open the file, err is %+v", err)
	}
	defer fs.Close()
	r := csv.NewReader(fs)
	//针对大文件,一行一行的读取文件
	for {
		row, err := r.Read()
		if err != nil && err != io.EOF {
			log.Fatalf("can not read, err is %+v", err)
		}
		if err == io.EOF {
			break
		}
		fmt.Println(row)
	}
	fmt.Println("\n---------------------------\n")
	// 针对小文件,也可以一次性读取所有的文件。注意,r要重新赋值,因为readall是读取剩下的
	fs1, _ := os.Open(fileName)
	r1 := csv.NewReader(fs1)
	content, err := r1.ReadAll()
	if err != nil {
		log.Fatalf("can not readall, err is %+v", err)
	}
	for _, row := range content {
		fmt.Println(row)
	}
}

  • 执行程序(go run main.go),执行后输出入下日志:
[序号 姓名 年龄 月薪]
[1 小李, 23 2300]
[2 小张 23 2500]
[3 小马 23 5000]

---------------------------

[序号 姓名 年龄 月薪]
[1 小李, 23 2300]
[2 小张 23 2500]
[3 小马 23 5000]

快速导出文件

  • 程序
package main

import (
	"encoding/csv"
	"fmt"
	"math/rand"
	"os"
	"strconv"
	"time"
)

// 产生一个随机数
func RandInt(min, max int) int {
	if min >= max || min == 0 || max == 0 {
		return max
	}
	return rand.Intn(max-min) + min
}

func main() {
  // 程序开始
	fmt.Printf("csv demo started:%s\n", time.Now().Format("2006-01-02 15:05:02"))
	//创建csv文件
	f, err := os.Create("test.csv")
	if err != nil {
		panic(err)
	}
	//异步管理
	defer f.Close()
	// 写入UTF-8 BOM
	f.WriteString("\xEF\xBB\xBF")
	//创建一个新的写入文件流
	w := csv.NewWriter(f)

  // 定义内容长度
	length := 300000
	fmt.Printf("start create data: time=%v,len=%d\n",time.Now().Format("2006-01-02 15:05:02"),length)
	data := make([][]string, length + 1 )  //创建第一维长度
	for i := range data{
		data[i]= make([]string,4) //创建第二维长度
	}
  // 填充第一行数据
	data[0][0] = "序号"
	data[0][1] = "姓名"
	data[0][2] = "年龄"
	data[0][3] = "月薪"

  // 随机生成数据,实际工作中这部分数据应该从数据库内获取
	for i:=0; i<length; i++ {
    // 填充第2~N行数据
		data[i+1][0] = strconv.Itoa(i)
		data[i+1][1] = "姓名"+ strconv.Itoa(i)
		data[i+1][2] = strconv.Itoa(RandInt(15,30))
		data[i+1][3] = strconv.Itoa(RandInt(2000,5000))
	}
	fmt.Printf("create data success: time=%v,len=%d\n",time.Now().Format("2006-01-02 15:05:02"),length)

	//写入数据
	w.WriteAll(data)
	w.Flush()
	fmt.Printf("save data success: time=%v,len=%d\n",time.Now().Format("2006-01-02 15:05:02"),length)
}

  • 发现执行时间很快,基本上1秒内完成了相关工作,在m级别的数据上,应该够用了

快速导出文件(大文件处理)

上一个章节,笔者把所有内容都加载到内存内,如果导出文件是一个很大的文件该方案可能会传OOM的情况。为解决该问题可修改成如下方案:

数据读取分块
读取数据块1
导出文件1
读取数据块2
导出文件2
读取数据块3
导出文件3
合并文件
更多块...
(完)