Go 数据存储篇(三):通过 CSV 格式读写文本数据

Go语言精选

共 3883字,需浏览 8分钟

 ·

2020-09-10 20:45

上篇教程中,给大家演示了如何通过 JSON 编码存储文本数据到磁盘文件,除此之外,Go 语言还提供了对 CSV 格式文件的支持,CSV 文件本质上虽然就是文本格式数据,不过可以兼容 Excel 表格,这样一来就可以极大方便我们对大批量数据进行管理。

使用 encoding/csv 包读写 CSV 文件

在 Go 语言中,可以通过官方提供的 encoding/csv 包来操作 CSV 文件的写入和读取,我们新建一个 csv.go 文件,并编写一段示例代码如下:

package main

import (
    "encoding/csv"
    "fmt"
    "os"
    "strconv"
)

type Tutorial struct {
    Id int
    Title string
    Summary string
    Author string
}

func main()  {
    // 创建一个 tutorials.csv 文件
    csvFile, err := os.Create("tutorials.csv")
    if err != nil {
        panic(err)
    }
    defer csvFile.Close()

    // 初始化字典数据
    tutorials := []Tutorial{
        Tutorial{Id: 1, Title: "Go 入门编程", Summary: "Go 基本语法和使用示例", Author: "学院君"},
        Tutorial{Id: 2, Title: "Go Web 编程", Summary: "Go Web 编程入门指南", Author: "学院君"},
        Tutorial{Id: 3, Title: "Go 并发编程", Summary: "通过并发编程提升性能", Author: "学院君"},
        Tutorial{Id: 4, Title: "Go 微服务开发", Summary: "基于 go-micro 框架开发微服务", Author: "学院君"},
    }

    // 初始化一个 csv writer,并通过这个 writer 写入数据到 csv 文件
    writer := csv.NewWriter(csvFile)
    for _, tutorial := range tutorials {
        line := []string{
            strconv.Itoa(tutorial.Id),  // 将 int 类型数据转化为字符串
            tutorial.Title,
            tutorial.Summary,
            tutorial.Author,
        }
        // 将切片类型行数据写入 csv 文件
        err := writer.Write(line)
        if err != nil {
            panic(err)
        }
    }
    // 将 writer 缓冲中的数据都推送到 csv 文件,至此就完成了数据写入到 csv 文件
    writer.Flush()

    // 打开这个 csv 文件
    file, err := os.Open("tutorials.csv")
    if err != nil {
        panic(err)
    }
    defer file.Close()

    // 初始化一个 csv reader,并通过这个 reader 从 csv 文件读取数据
    reader := csv.NewReader(file)
    // 设置返回记录中每行数据期望的字段数,-1 表示返回所有字段
    reader.FieldsPerRecord = -1
    // 通过 readAll 方法返回 csv 文件中的所有内容
    record, err := reader.ReadAll()
    if err != nil {
        panic(err)
    }

    // 遍历从 csv 文件中读取的所有内容,并将其追加到 tutorials2 切片中
    var tutorials2 []Tutorial
    for _, item := range record {
        id, _ := strconv.ParseInt(item[0], 00)
        tutorial := Tutorial{Id: int(id), Title: item[1], Summary: item[2], Author: item[3]}
        tutorials2 = append(tutorials, tutorial)
    }

    // 打印 tutorials2 的第一个元素验证 csv 文件写入/读取是否成功
    fmt.Println(tutorials2[0].Id)
    fmt.Println(tutorials2[0].Title)
    fmt.Println(tutorials2[0].Summary)
    fmt.Println(tutorials2[0].Author)
}

可以看到新建文件、打开文件、关闭文件和上篇教程操作普通的磁盘文件并无区别,不过这里为了支持通过 CSV 格式写入和读取文件,我们在文件句柄之上套了一层 CSV Writer 和 CSV Reader,这有点像适配器模式,然后我们就可以通过 CSV Writer 写入数据到 CSV 文件,通过 CSV Reader 读取 CSV 文件了:

...

// 初始化一个 csv writer,并通过这个 writer 写入数据到 csv 文件
writer := csv.NewWriter(csvFile)

...

// 初始化一个 csv reader,并通过这个 reader 从 csv 文件读取数据
reader := csv.NewReader(file)  

...

除了 CSV 之外,Go 官方提供的 encoding 包还提供了对其他格式文件编解码的支持,比如 JSON、XML、Gob 等:


使用方法了操作 CSV 文件一致,这也是 Go 语言设计之美的体现,通过接口与组合的方式可以很方便的构建起复杂的业务功能,感兴趣的同学可以去看下 Go 官方的 io 包实现源码。

另外,这里也可以体现出通过 os 包获取文件句柄进行操作相较于 ioutil 读写文件的优势:可以在文件句柄上套其他处理器进行更加灵活、复杂的操作,而 ioutil 包只能简单进行数据写入与读取而已。

关于上述代码的实现细节,都已经通过详细的注释标注了,我们重点关注如何将数据写入 CSV 文件,以及如何从 CSV 文件读取数据即可。

运行上述代码,返回结果如下,说明 CSV 文件写入和读取成功:

当然,你也可以在此基础上扩展出 CSV 文件数据的增删改查功能,感兴趣的同学可以自己尝试下,这里就具体展开了。

使用不同软件预览 CSV 文件

除了通过代码验证之外,还可以直接打开 csv.go 同级目录下生成的 tutorials.csv 文件,这就是一个纯文本文件,只是不同字段之间用逗号分隔,不同记录之间用换行符分隔而已:


在 Mac 系统中,你可以通过 Numbers 应用打开这个文件进行预览,格式化后的数据就好看多了:

在 Windows 中,可以通过 Excel 软件打开这个文件,但是现在看到的是乱码数据:

这是因为 Excel 默认并不是 UTF-8 编码,因此要解决这个乱码问题,可以在对应的 CSV 文件写入 UTF-8 BOM 头,告知 Excel 通过 UTF-8 编码打开这个文件:

...

// 写入 UTF-8 BOM,防止中文乱码
csvFile.WriteString("\xEF\xBB\xBF")

// 初始化一个 csv writer,并通过这个 writer 写入数据到 csv 文件
writer := csv.NewWriter(csvFile)

...

再次运行程序,通过 Excel 打开 tutorials.csv,就可以看到正常渲染的数据了:

关于 Excel 文件的读取和写入,学院君就简单介绍到这里,这里留一个课后作业,参考 encoding/csv 包读写 CSV 文件的方式,试着编写一段使用 encoding/json 包读写 JSON 文件的代码并正常运行起来,看看生成的文件是否符合预期。

(全文完)




推荐阅读



学习交流 Go 语言,扫码回复「进群」即可


站长 polarisxu

自己的原创文章

不限于 Go 技术

职场和创业经验


Go语言中文网

每天为你

分享 Go 知识

Go爱好者值得关注



浏览 30
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报