如何在Golang中读写CSV数据

GoCSV教程展示了如何在Golang中读写CSV数据。

CSV

CSV(逗号分隔值)是电子表格和数据库中使用的一种非常流行的导入和导出数据格式。CSV文件中的每一行都是一个数据记录。每条记录由一个或多个字段组成,以逗号分隔。虽然CSV是一种非常简单的数据格式,但可能存在许多差异,例如不同的分隔符、换行符或引号字符。

Golang有encoding/csv包来处理CSV。它提供读取和写入逗号分隔值(CSV)文件的功能。CSV文件包含零条或多条记录,每条记录有一个或多个字段。每条记录由换行符分隔。最后的记录后面可以有选择地跟一个换行符。空白被认为是字段的一部分。空行被忽略。

$ go version
go version go1.18.1 linux/amd64

我们使用Go版本1.18。

进行CSV阅读

Read函数从读取器读取一条记录(一段字段)。

1,2,3,4,5
6,7,8,9,10

这是numbers.csv文件。

package main

import (
    "encoding/csv"
    "fmt"
    "io"
    "log"
    "os"
)

func main() {

    f, err := os.Open("numbers.csv")

    if err != nil {

        log.Fatal(err)
    }

    r := csv.NewReader(f)

    for {

        record, err := r.Read()

        if err == io.EOF {
            break
        }

        if err != nil {
            log.Fatal(err)
        }

        for value := range record {
            fmt.Printf("%s\n", record[value])
        }
    }
}

在代码示例中,我们从numbers.csv文件中读取值。

for {

    record, err := r.Read()

    if err == io.EOF {
        break
    }

    if err != nil {
        log.Fatal(err)
    }    

    for value := range record {
        fmt.Printf("%s\n", record[value])
    }
}

使用Read函数逐行读取for循环中的值。

$ go run read_fun.go
1
2
3
4
5
6
7
8
9
10

转到CSVReadAll

ReadAll函数从阅读器中读取所有剩余的记录。每条记录都是一片字段。

first_name,last_name,occupation
John,Doe,gardener
Lucy,Smith,teacher
Brian,Bethamy,programmer

这是users.csv文件。第一行是列名。

package main

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

type User struct {
    firstName  string
    lastName   string
    occupation string
}

func main() {

    records, err := readData("users.csv")

    if err != nil {
        log.Fatal(err)
    }

    for _, record := range records {

        user := User{
            firstName:  record[0],
            lastName:   record[1],
            occupation: record[2],
        }

        fmt.Printf("%s %s is a %s\n", user.firstName, user.lastName,
            user.occupation)
    }
}

func readData(fileName string) ([][]string, error) {

    f, err := os.Open(fileName)

    if err != nil {
        return [][]string{}, err
    }

    defer f.Close()

    r := csv.NewReader(f)

    // skip first line
    if _, err := r.Read(); err != nil {
        return [][]string{}, err
    }

    records, err := r.ReadAll()

    if err != nil {
        return [][]string{}, err
    }

    return records, nil
}

该示例读取users.csv文件。每行变成一个User类型。

// skip first line
if _, err := r.Read(); err != nil {
    return [][]string{}, err
}

这里我们跳过第一行,其中包含列名。

records, err := r.ReadAll()

我们使用ReadAll一次性获取所有记录。

$ go run read_all.go
John Doe is a gardener
Lucy Smith is a teacher
Brian Bethamy is a programmer

GoCSV不同的分隔符

尽管名称如此,但CSV可能包含逗号以外的其他分隔符。这是由于CSV格式缺乏标准化所致。

# this is users.csv file

John;Doe;gardener
Lucy;Smith;teacher
Brian;Bethamy;programmer

users.csv文件中,字段以分号分隔。该文件还包含注释。

package main

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

func main() {

    f, err := os.Open("users.csv")

    if err != nil {

        log.Fatal(err)
    }

    r := csv.NewReader(f)
    r.Comma = ';'
    r.Comment = '#'

    records, err := r.ReadAll()

    if err != nil {
        log.Fatal(err)
    }

    fmt.Print(records)
}

该示例从该文件中读取所有数据。

r := csv.NewReader(f)
r.Comma = ';'
r.Comment = '#'

这里我们设置了分隔符和注释符,这样包就知道如何解析文件了。

进行CSV写入

Write函数将单个CSV记录写入writer。一条记录是一段字符串,每个字符串是一个字段。写入被缓冲,因此必须调用Flush以确保将记录写入底层写入器。

package main

import (
    "encoding/csv"
    "log"
    "os"
)

func main() {

    records := [][]string{
        {"first_name", "last_name", "occupation"},
        {"John", "Doe", "gardener"},
        {"Lucy", "Smith", "teacher"},
        {"Brian", "Bethamy", "programmer"},
    }

    f, err := os.Create("users.csv")
    defer f.Close()

    if err != nil {

        log.Fatalln("failed to open file", err)
    }

    w := csv.NewWriter(f)
    defer w.Flush()

    for _, record := range records {
        if err := w.Write(record); err != nil {
            log.Fatalln("error writing record to file", err)
        }
    }
}

在代码示例中,我们使用Write函数将几条记录写入users.csv文件。

转到CSVWriteAll

WriteAll函数使用Write将多个CSV记录写入writer,然后调用Flush

package main

import (
    "encoding/csv"
    "log"
    "os"
)

func main() {

    records := [][]string{
        {"first_name", "last_name", "occupation"},
        {"John", "Doe", "gardener"},
        {"Lucy", "Smith", "teacher"},
        {"Brian", "Bethamy", "programmer"},
    }

    f, err := os.Create("users.csv")
    defer f.Close()

    if err != nil {

        log.Fatalln("failed to open file", err)
    }

    w := csv.NewWriter(f)
    err = w.WriteAll(records) // calls Flush internally

    if err != nil {
        log.Fatal(err)
    }
}

我们使用WriteAll一次性写入多条记录。

在本教程中,我们展示了如何在Golang中读取和写入CSV数据。

(adsbygoogle=window.adsbygoogle||[]).push({});

列出所有Go教程。

赞(0) 打赏

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏