Go语言处理csv文件数据
Go自带的库文件encoding/csv 可以用来解析 csv 文件,本例子将演示通过标准库文件以及数据帧两种方式解析csv文件
一、通过标准库文件encoding/csv
1、首先我们制作一个csv文件,此文件字段之间通过逗号分隔,如图:

2、定义go文件,打开csv文件并读取,如图:

- 通过Open()打开文件,返回os库的File结构体,此结构体实现了io.Reader接口,注意Open()需要关闭
- 通过csv库的NewReader()读取打开后的文件,返回csv库的Reader结构体指针,NewReader参数为io.Reader接口,File也实现了此接口,因此 f 可以直接作为参数传递
- 通过for无限循环以及Reader结构体的Read()方法读取内容,返回字符串切片
- io.EOF:数据读取结束后会返回EOF,因此判断err等于io.EOF时此时表示数据已经读取完毕
- 最后将读取的数据添加到定义的二维切片中
除了上面Read()方法还可以通过ReadAll()方法直接返回二维切片,如图:

最终打印结果如图:

注意:如果csv文件不是以逗号分隔或者文件中包含注释的行,此时可以使用csv.Reader.Comma和csv.Reader.Comment来处理
向csv中写入文件
1、首先查看csv文件内容,注意在将此csv文件上传到Linux之前确认好编码为utf-8,如图:

2、获取每行的日期数据的年份差值,放在行后,并输出到新文件中,如下:
package main
import (
"encoding/csv"
"io"
"log"
"os"
"strconv"
"strings"
)
func main() {
f, err := os.Open("./test.csv")
if err != nil {
log.Fatal(err)
}
defer f.Close()
rd := csv.NewReader(f)
var res [][]string
for {
rs, err := rd.Read() //读取结果为切片
if err == io.EOF {
break
}
res = append(res, rs) //将切片添加到二位切片中
}
for _, v := range res {
//获取年份
i, err := strconv.Atoi(strings.Split(v[1], "/")[0])
if err != nil {
log.Fatal(err)
}
j, err := strconv.Atoi(strings.Split(v[0], "/")[0])
if err != nil {
log.Fatal(err)
}
ii := i - j //年份相减
v = append(v, strconv.Itoa(ii)) //追加到切片v的后面
f1, err := os.OpenFile("./res.csv", os.O_CREATE|os.O_RDWR|os.O_APPEND, 0666)
if err != nil {
log.Fatal(err)
}
wr := csv.NewWriter(f1) //创建写对象
err = wr.Write(v) //调用写方法,参数为字符串切片
if err != nil {
log.Fatal(err)
}
wr.Flush() //最后从缓存区写入到文件中
defer f1.Close()
}
}
最后的结果为:

处理非预期的域
有时候的csv文件并不都是像上面的那样整洁干净,可能很乱,此时可以通过reader.FieldsPerRecord来处理,FieldsPerRecord说明如下:
FieldsPerRecord是每个记录(行)所需的字段数。
如果FieldsPerRecord为正,则Read要求每个记录具有给定数量的字段。
如果FieldsPerRecord为0,Read将其设置为第一条记录中的字段数,以便将来的记录必须具有相同的字段计数。
如果FieldsPerRecord为负数,则不进行检查制作和记录可能有可变数量的字段
1、修改上述的csv文件,新增4、5字段,如图:

没有添加4、5之前,每个域字段数为8个,现在第三行字段数为10个
再次执行上面的go文件,可以看到报错了,如图:

针对上述错误,有两种解决方法:
第一种,设置FieldsPerRecord的值为负数,不进行检查和记录字段数,如图:

运行结果如下:

第二种,设置域字段FieldsPerRecord数量为8,并获取符合条件的记录数,其余的排除掉,如图:

运行结果如下,已获取到符合要求的数据:

注:如果设置FieldsPerRecord为10,将获取第三条数据,前两条被废弃
二、通过数据帧操作CSV数据
对于复杂的CSV文件,通过标准库encoding/csv处理可能会很麻烦并且效果未必很好,此时可以通过数据帧来操作,本例子演示的相关数据帧程序包为dataframe,地址为:
https://github.com/go-gota/gota
https://pkg.go.dev/github.com/kniren/gota/dataframe#DataFrame
1、定义csv文件,包含列名和字段名,如图:

2、通过dataframe来过滤出IP为192.168.1.1的行,如图:

运行结果如下:

上图中的Filter()方法是可以添加多个F结构体参数的,如果要匹配多个字段,可写为:


3、通过dataframe过滤出IP为192.168.1.1的IP、use、remarks字段,通过Select()方法,如图:

运行结果如下:

Select()方法的只有一个参数,为一个空接口,可以接受任意类型的参数,因此如果要匹配多个字段只能通过切片方式实现
4、更新文件的第3和第4行数据,如图:

运行结果如下:

注意:此数据是读取后更新的,源文件内容没变
更多用法自行参考文档实现!!!


