要在Go中轻松读取和解析CSV(或TSV)文件,你可以使用两种方法 encoding/csv包。
csv.Reader.ReadAll()一次性读取并解析整个文件。但是请注意,一个非常大的文件可能无法容纳在内存中。csv.Reader.Read()来逐行读取CSV文件。
在下面的例子中,我们使用
data.csv文件。vegetables,fruits carrot,banana potato,strawberry
一次性读取整个CSV文件
在这个例子中,我们打开CSV文件,初始化 csv.Reader并将所有数据读入一个[][]string slice,其中第一个索引是文件的行号,第二个索引是这一行中逗号分隔的值的索引。我们可以对这些数据做一些处理,例如,转换为一个结构数组。
package main
import (
"encoding/csv"
"fmt"
"log"
"os"
)
type ShoppingRecord struct {
Vegetable string
Fruit string
}
func createShoppingList(data [][]string) []ShoppingRecord {
var shoppingList []ShoppingRecord
for i, line := range data {
if i > 0 { // omit header line
var rec ShoppingRecord
for j, field := range line {
if j == 0 {
rec.Vegetable = field
} else if j == 1 {
rec.Fruit = field
}
}
shoppingList = append(shoppingList, rec)
}
}
return shoppingList
}
func main() {
// open file
f, err := os.Open("data.csv")
if err != nil {
log.Fatal(err)
}
// remember to close the file at the end of the program
defer f.Close()
// read csv values using csv.Reader
csvReader := csv.NewReader(f)
data, err := csvReader.ReadAll()
if err != nil {
log.Fatal(err)
}
// convert records to array of structs
shoppingList := createShoppingList(data)
// print the array
fmt.Printf("%+v\n", shoppingList)
}
输出
[{Vegetable:carrot Fruit:banana} {Vegetable:potato Fruit:strawberry}]
逐行读取一个CSV文件
逐行读取与一次性读取整个文件类似,但在这种情况下,我们用 csv.Reader.Read()方法来读取无限循环中的下一行数据。当没有更多的数据可用时,这个循环就会退出,即。 io.EOF错误发生。
package main
import (
"encoding/csv"
"fmt"
"io"
"log"
"os"
)
func main() {
// open file
f, err := os.Open("data.csv")
if err != nil {
log.Fatal(err)
}
// remember to close the file at the end of the program
defer f.Close()
// read csv values using csv.Reader
csvReader := csv.NewReader(f)
for {
rec, err := csvReader.Read()
if err == io.EOF {
break
}
if err != nil {
log.Fatal(err)
}
// do something with read line
fmt.Printf("%+v\n", rec)
}
}
输出
[vegetables fruits]
[carrot banana]
[potato strawberry]
使用非默认的字段分隔符并读取一个TSV文件
的标准分隔符是 csv.Reader的标准分隔符是逗号,但很容易将其改为任何符文。例如,你可以把它改为制表符\t ,这样,你就得到了TSV阅读器。
csvReader.Comma = '\t'