golang 读写CSV文件

日常工作中需要基于数据生成报表,常要求输出CSV文件,于是基于golang的反射机制和标准库实现了一个CSV读写包,可以将结构体或者结构体列表直接输出CSV文件。或者CSV文件内容直接读取到结构体或者结构体列表。提高效率。项目已经开源,希望能对您有所帮助,如果确实有幸帮到了您,请帮我在git仓库里点个star,鼓励我一下。

详见:GitHub - CXeon/easy_csv: A simple csv library based on golang.

用法如下:

安装:go get -u github.com/CXeon/easy_csv

如果您想将1个结构体输出到CSV文件,您可以这样:

package main

import (
	"github.com/CXeon/easy_csv"
	"os"
)

type testStudentInfo struct {
	Name  string `csv:"name"`
	Age   int
	Grade string
	Score float64 `csv:"mScore"`
	Email string  `csv:"mEmail,email_desensitization"` //The email_desensitization will desensitize email addresses.The email username must be greater than 3 characters to be effective.
	Phone string  `csv:"mPhone,phone_desensitization"` //The phone_desensitization will desensitize the phone number.The mobile phone number must be greater than 6 digits to be effective.
}

func main() {
	fileName := "./CsvWriter.csv"

	csvFile, err := os.OpenFile(fileName, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
	if err != nil {
		panic(err)
	}
	defer csvFile.Close()

	clientWriter := easy_csv.NewClientWriter(csvFile)

	//clientWriter.WriteString2File()

	row := testStudentInfo{
		Name:  "Jam",
		Age:   10,
		Grade: "Grade 4",
		Score: 99.01,
		Email: "jamjam@test.com",
		Phone: "13322226666",
	}

	// parameter row cloud be &row
	err = clientWriter.WriteRow2File(row, true)
	if err != nil {
		panic(err)
	}

}

如代码所示,您可以使用结构体标签"csv"来指定列名,使用email_desensitization和phone_desensitization来分别对邮箱和手机号进行脱敏。如果没有使用csv标签指定列名,结果会使用结构体属性名称来做列名。当然,您可以在调用输出文件的相关方法时设置参数,是否要生成对应的列名。

上面的代码产生的文件内容是:

nameAgeGrademScoremEmailmPhone
Jam10Grade 499.01ja***m@test.com133****6666

如果您想将一组数据写入到csv文件,您可以这样:

package main

import (
	"github.com/CXeon/easy_csv"
	"os"
)

type testStudentInfo struct {
	Name  string `csv:"name"`
	Age   int
	Grade string
	Score float64 `csv:"mScore"`
	Email string  `csv:"mEmail,email_desensitization"` //The email_desensitization will desensitize email addresses.The email username must be greater than 3 characters to be effective.
	Phone string  `csv:"mPhone,phone_desensitization"` //The phone_desensitization will desensitize the phone number.The mobile phone number must be greater than 6 digits to be effective.
}

func main() {
	fileName := "./CsvWriter.csv"

	csvFile, err := os.OpenFile(fileName, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
	if err != nil {
		panic(err)
	}
	defer csvFile.Close()

	clientWriter := easy_csv.NewClientWriter(csvFile)

	list := []testStudentInfo{
		{
			Name:  "Jam",
			Age:   10,
			Grade: "Grade 4",
			Score: 99.01,
			Email: "jamjam@test.com",
			Phone: "13322226666",
		},
		{
			Name:  "xeon",
			Age:   13,
			Grade: "Grade 6",
			Score: 101.11,
			Email: "xeonjoe@test.com",
			Phone: "16542354654",
		},
	}

	// parameter list  cloud be &list.the item of list cloud be a structure pointer
	err = clientWriter.WriteRows2File(list, true)
	if err != nil {
		panic(err)
	}

}

以上代码生成的csv文件内容是:

nameAgeGrademScoremEmailmPhone
Jam10Grade 499.01ja***m@test.com133****6666
xeon13Grade 6101.11xe***e@test.com165****4654

比如有一个csv文件的内容是:

nameAgeGrademScoremEmailmPhone
Jam10Grade 499.01ja***m@test.com133****6666
xeon13Grade 6101.11xe***e@test.com165****4654
bob10Grade 499.01bo***i@test.com133****6666

您也可以将csv文件的数据直接读取一行到结构体:

package main

import (
	"fmt"
	"github.com/CXeon/easy_csv"
	"os"
)

type testStudentInfo struct {
	Name  string 
	Age   int
	Grade string
	Score float64 
	Email string   
	Phone string  
}

func main() {
	fileName := "./CsvReader.csv"

	csvFile, err := os.OpenFile(fileName, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
	if err != nil {
		panic(err)
	}
	defer csvFile.Close()

	clientReader := easy_csv.NewClientReader(csvFile)

	clientReader.Read() //Important.Exclude title

	data := testStudentInfo{}
	err = clientReader.ReadRowFromFile(&data)
	if err != nil {
		panic(err)
	}

	fmt.Printf("%#v\n", data)
}

打印的结果是:

main.testStudentInfo{Name:"Jam", Age:10, Grade:"Grade 4", Score:99.01, Email:"jam@test.com", Phone:"133*6666"}

以上代码会将csv文件的列按顺序依次解析到结构体的每个属性,实际使用中csv文件中每一列和结构体属性的顺序并不一定是一一对应的,所以您可以这样:

package main

import (
	"fmt"
	"github.com/CXeon/easy_csv"
	"os"
)

type testStudentInfo struct {
	Score float64 
	Email string 
	Phone string  
	Name  string 
	Age   int
	Grade string
}

func main() {
	fileName := "./CsvReader.csv"

	csvFile, err := os.OpenFile(fileName, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
	if err != nil {
		panic(err)
	}
	defer csvFile.Close()

	clientReader := easy_csv.NewClientReader(csvFile)

	clientReader.Read() //Important.Exclude title

	data := testStudentInfo{}

	names := []string{
		"Name",
		"Age",
		"Grade",
		"Score",
		"Email",
		"Phone",
	}
	err = clientReader.ReadRowFromFileWithNames(names, &data)
	if err != nil {
		panic(err)
	}

	fmt.Printf("%#v\n", data)
}

以上代码在方法中指定了一个names切片,元素是结构体属性名,用来告知方法将csv文件的列依次解析到结构体的哪个属性。打印的结果是:

main.testStudentInfo{Score:99.01, Email:"jam@test.com", Phone:"133*6666", Name:"Jam", Age:10, Grade:"Grade 4"}

通常在工作中需要一次读取多行数据:

package main

import (
	"fmt"
	"github.com/CXeon/easy_csv"
	"os"
)

type testStudentInfo struct {
	Name  string 
	Age   int
	Grade string
	Score float64 
	Email string  
	Phone string  
}

func main() {
	fileName := "./CsvReader.csv"

	csvFile, err := os.OpenFile(fileName, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
	if err != nil {
		panic(err)
	}
	defer csvFile.Close()

	clientReader := easy_csv.NewClientReader(csvFile)

	clientReader.Read() //Important.Exclude title

	var list []testStudentInfo
	// var list  []*testStudentInfo //yes
	err = clientReader.ReadRowsFromFile(&list)
	if err != nil {
		panic(err)
	}

	fmt.Printf("%#v\n", list)
}

以上代码同样是将csv文件的列按顺序依次解析到结构体的每个属性,打印的结果是:

[]main.testStudentInfo{main.testStudentInfo{Name:"Jam", Age:10, Grade:"Grade 4", Score:99.01, Email:"jam@test.com", Phone:"1336666"}, main.testStudentInfo{Name:"xeon", Age:13, Grade:"Grade 5", Score:101.11, Email:"xee@test.com", Phone:"1654654"}, main.testStudentInfo{Name:"bob", Age:10, Grade:"Grade 4", Score:99.01, Email:"boi@test.com", Phone:"133***6666"}}

如果结构体属性的顺序和列名顺序不一致 ,还是可以这样做:

package main

import (
	"fmt"
	"github.com/CXeon/easy_csv"
	"os"
)

type testStudentInfo struct {
	Score float64
	Email string  
	Phone string  
	Name  string 
	Age   int
	Grade string
}

func main() {
	fileName := "./CsvReader.csv"

	csvFile, err := os.OpenFile(fileName, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
	if err != nil {
		panic(err)
	}
	defer csvFile.Close()

	clientReader := easy_csv.NewClientReader(csvFile)

	clientReader.Read() //Important.Exclude title

	var list []testStudentInfo
	// var list  []*testStudentInfo //yes
	names := []string{
		"Name",
		"Age",
		"Grade",
		"Score",
		"Email",
		"Phone",
	}
	err = clientReader.ReadRowsFromFileWithNames(names, &list)
	if err != nil {
		panic(err)
	}

	fmt.Printf("%#v\n", list)
}

打印的结果是:

[]main.testStudentInfo{main.testStudentInfo{Score:99.01, Email:"jam@test.com", Phone:"1336666", Name:"Jam", Age:10, Grade:"Grade 4"}, main.testStudentInfo{Score:101.11, Email:"xee@test.com", Phone:"1654654", Name:"xeon", Age:13, Grade:"Grade 5"}, main.testStudentInfo{Score:99.01, Email:"boi@test.com", Phone:"133***6666", Name:"bob", Age:10, Grade:"Grade 4"}}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值