本文主要介绍go如何读取和写入csv文件,以及使用第三方库gocsv转换为Struct。

读取csv

go 标准库 “encoding/csv” 用于读写csv文件。

Reader从csv编码的文件中读取记录

  • type Reader
    • func NewReader(r io.Reader) *Reader
    • func (r *Reader) Read() (record []string, err error) 。
    • func (r *Reader) ReadAll() (records [][]string, err error)

创建一个csv文件servers.csv,具体如下

world-svc,1/1,Running,0,44m
battle-svc,1/1,Running,0,7d

ReadAll从r中读取所有剩余的记录,每个记录都是字段的切片,成功的调用返回值err为nil而不是EOF。因为ReadAll方法定义为读取直到文件结尾,因此它不会将文件结尾视为应该报告的错误。

package main

import (
	"encoding/csv"
	"fmt"
	"io"
	"os"
)
func main() {
	readeCsvAll() 
}
func readerCsvReadAll() {
	file, err := os.Open("servers.csv")
	defer file.Close()
	if err != nil {
		fmt.Println(err)
	}
	reader := csv.NewReader(file)
	servers, _ := reader.ReadAll()
	fmt.Println("ReadAll:", servers)
}

OutPut:

ReadAll:  [world-svc 1/1 Running 0 44m] [battle-svc 1/1 Running 0 7d]]

Read从r读取一条记录,返回值record是字符串的切片,每个字符串代表一个字段。

reader := csv.NewReader(file)
for {
    servers, err := reader.Read()
    if err == io.EOF {
        break
    } else if err != nil {
        fmt.Println("Error:", err)
        return
    }
    fmt.Println(servers)
}

输出和ReadAll是一样的。

csv读写逗号分隔值(csv)的文件,亦或可以定义数据的分隔符

reader.Comma = '|' 

亦或可以定义忽略的的行

reader.Comment = '#'

写入csv

Writer类型的值将记录写入一个csv编码的文件

  • type Writer
    • func NewWriter(w io.Writer) *Writer
    • func (w *Writer) Write(record []string) (err error)
    • func (w *Writer) WriteAll(records [][]string) (err error)
    • func (w *Writer) Flush()
    • func (w *Writer) Error() error

向w中写入一条记录,会自行添加必需的引号。记录是字符串切片,每个字符串代表一个字段。

func writerOne() {
	servers := []Server{
		{"world-svc", "1/1", "Running", 0, "44m"},
		{"battle-svc", "1/1", "Running", 0, "7d"},
	}
	file, err := os.Create("serversA.csv")
	defer file.Close()
	if err != nil {
		log.Fatalln("failed to open file", err)
	}
	w := csv.NewWriter(file)
   //将缓存中的数据写入底层的io.Writer。
	defer w.Flush()
	// 使用 Write
	for _, server := range servers {
		row := []string{server.Name, server.Ready, server.State, strconv.Itoa(server.Restarts), server.Age}
		if err := w.Write(row); err != nil {
			log.Fatalln("error writing server to file", err)
		}
	}

执行,在当前目录生成 serversA.csv,内容如下:

world-svc,1/1,Running,0,44m
battle-svc,1/1,Running,0,7d

WriteAll方法使用Write方法向w写入多条记录,并在最后调用Flush方法清空缓存

	var data [][]string
	for _, server := range servers {
		row := []string{server.Name, server.Ready, server.State, strconv.Itoa(server.Restarts), server.Age}
		data = append(data, row)
	}
	w.WriteAll(data)

To Struct

GoCSV包旨在提供 CSV 和 Go (golang) 值之间的快速和惯用的映射。 已有servers.csv 内容如下

Name,Ready,Status,Restart,Age
world-svc,1/1,Running,0,44m
battle-svc,1/1,Running,0,7d

UnmarshalFile(in *os.File, out interface{}) error UnmarshalFile从接口中的文件解析CSV。

func ToStruct() {
	clientsFile, err := os.OpenFile("servers.csv", os.O_RDWR|os.O_CREATE, os.ModePerm)
	if err != nil {
		panic(err)
	}
	defer clientsFile.Close()

	var servers []*Server
    //转换成 Server Object
	if err := gocsv.UnmarshalFile(clientsFile, &servers); err != nil {  
		panic(err)
	}
	for _, server := range servers {
		fmt.Println("Server", server.Name)
	}
}

OuPut:

Server world-svc
Server battle-svc

更多api使用方式可参考:https ://github.com/gocarina/gocsv

参考