日常工作中需要基于数据生成报表,常要求输出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标签指定列名,结果会使用结构体属性名称来做列名。当然,您可以在调用输出文件的相关方法时设置参数,是否要生成对应的列名。
上面的代码产生的文件内容是:
name | Age | Grade | mScore | mEmail | mPhone |
---|---|---|---|---|---|
Jam | 10 | Grade 4 | 99.01 | ja***m@test.com | 133****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文件内容是:
name | Age | Grade | mScore | mEmail | mPhone |
---|---|---|---|---|---|
Jam | 10 | Grade 4 | 99.01 | ja***m@test.com | 133****6666 |
xeon | 13 | Grade 6 | 101.11 | xe***e@test.com | 165****4654 |
比如有一个csv文件的内容是:
name | Age | Grade | mScore | mEmail | mPhone |
---|---|---|---|---|---|
Jam | 10 | Grade 4 | 99.01 | ja***m@test.com | 133****6666 |
xeon | 13 | Grade 6 | 101.11 | xe***e@test.com | 165****4654 |
bob | 10 | Grade 4 | 99.01 | bo***i@test.com | 133****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"}}