Go 數(shù)據(jù)存儲篇(三):通過 CSV 格式讀寫文本數(shù)據(jù)
在上篇教程中,給大家演示了如何通過 JSON 編碼存儲文本數(shù)據(jù)到磁盤文件,除此之外,Go 語言還提供了對 CSV 格式文件的支持,CSV 文件本質(zhì)上雖然就是文本格式數(shù)據(jù),不過可以兼容 Excel 表格,這樣一來就可以極大方便我們對大批量數(shù)據(jù)進行管理。
使用 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()??{
????//?創(chuàng)建一個?tutorials.csv?文件
????csvFile,?err?:=?os.Create("tutorials.csv")
????if?err?!=?nil?{
????????panic(err)
????}
????defer?csvFile.Close()
????//?初始化字典數(shù)據(jù)
????tutorials?:=?[]Tutorial{
????????Tutorial{Id:?1,?Title:?"Go?入門編程",?Summary:?"Go?基本語法和使用示例",?Author:?"學(xué)院君"},
????????Tutorial{Id:?2,?Title:?"Go?Web?編程",?Summary:?"Go?Web?編程入門指南",?Author:?"學(xué)院君"},
????????Tutorial{Id:?3,?Title:?"Go?并發(fā)編程",?Summary:?"通過并發(fā)編程提升性能",?Author:?"學(xué)院君"},
????????Tutorial{Id:?4,?Title:?"Go?微服務(wù)開發(fā)",?Summary:?"基于?go-micro?框架開發(fā)微服務(wù)",?Author:?"學(xué)院君"},
????}
????//?初始化一個?csv?writer,并通過這個?writer?寫入數(shù)據(jù)到?csv?文件
????writer?:=?csv.NewWriter(csvFile)
????for?_,?tutorial?:=?range?tutorials?{
????????line?:=?[]string{
????????????strconv.Itoa(tutorial.Id),??//?將?int?類型數(shù)據(jù)轉(zhuǎn)化為字符串
????????????tutorial.Title,
????????????tutorial.Summary,
????????????tutorial.Author,
????????}
????????//?將切片類型行數(shù)據(jù)寫入?csv?文件
????????err?:=?writer.Write(line)
????????if?err?!=?nil?{
????????????panic(err)
????????}
????}
????//?將?writer?緩沖中的數(shù)據(jù)都推送到?csv?文件,至此就完成了數(shù)據(jù)寫入到?csv?文件
????writer.Flush()
????//?打開這個?csv?文件
????file,?err?:=?os.Open("tutorials.csv")
????if?err?!=?nil?{
????????panic(err)
????}
????defer?file.Close()
????//?初始化一個?csv?reader,并通過這個?reader?從?csv?文件讀取數(shù)據(jù)
????reader?:=?csv.NewReader(file)
????//?設(shè)置返回記錄中每行數(shù)據(jù)期望的字段數(shù),-1?表示返回所有字段
????reader.FieldsPerRecord?=?-1
????//?通過?readAll?方法返回?csv?文件中的所有內(nèi)容
????record,?err?:=?reader.ReadAll()
????if?err?!=?nil?{
????????panic(err)
????}
????//?遍歷從?csv?文件中讀取的所有內(nèi)容,并將其追加到?tutorials2?切片中
????var?tutorials2?[]Tutorial
????for?_,?item?:=?range?record?{
????????id,?_?:=?strconv.ParseInt(item[0],?0,?0)
????????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)
}
可以看到新建文件、打開文件、關(guān)閉文件和上篇教程操作普通的磁盤文件并無區(qū)別,不過這里為了支持通過 CSV 格式寫入和讀取文件,我們在文件句柄之上套了一層 CSV Writer 和 CSV Reader,這有點像適配器模式,然后我們就可以通過 CSV Writer 寫入數(shù)據(jù)到 CSV 文件,通過 CSV Reader 讀取 CSV 文件了:
...
//?初始化一個?csv?writer,并通過這個?writer?寫入數(shù)據(jù)到?csv?文件
writer?:=?csv.NewWriter(csvFile)
...
//?初始化一個?csv?reader,并通過這個?reader?從?csv?文件讀取數(shù)據(jù)
reader?:=?csv.NewReader(file)??
...
除了 CSV 之外,Go 官方提供的 encoding 包還提供了對其他格式文件編解碼的支持,比如 JSON、XML、Gob 等:

使用方法了操作 CSV 文件一致,這也是 Go 語言設(shè)計之美的體現(xiàn),通過接口與組合的方式可以很方便的構(gòu)建起復(fù)雜的業(yè)務(wù)功能,感興趣的同學(xué)可以去看下 Go 官方的 io 包實現(xiàn)源碼。
另外,這里也可以體現(xiàn)出通過 os 包獲取文件句柄進行操作相較于 ioutil 讀寫文件的優(yōu)勢:可以在文件句柄上套其他處理器進行更加靈活、復(fù)雜的操作,而 ioutil 包只能簡單進行數(shù)據(jù)寫入與讀取而已。
關(guān)于上述代碼的實現(xiàn)細節(jié),都已經(jīng)通過詳細的注釋標注了,我們重點關(guān)注如何將數(shù)據(jù)寫入 CSV 文件,以及如何從 CSV 文件讀取數(shù)據(jù)即可。
運行上述代碼,返回結(jié)果如下,說明 CSV 文件寫入和讀取成功:

當然,你也可以在此基礎(chǔ)上擴展出 CSV 文件數(shù)據(jù)的增刪改查功能,感興趣的同學(xué)可以自己嘗試下,這里就具體展開了。
使用不同軟件預(yù)覽 CSV 文件
除了通過代碼驗證之外,還可以直接打開 csv.go 同級目錄下生成的 tutorials.csv 文件,這就是一個純文本文件,只是不同字段之間用逗號分隔,不同記錄之間用換行符分隔而已:

在 Mac 系統(tǒng)中,你可以通過 Numbers 應(yīng)用打開這個文件進行預(yù)覽,格式化后的數(shù)據(jù)就好看多了:

在 Windows 中,可以通過 Excel 軟件打開這個文件,但是現(xiàn)在看到的是亂碼數(shù)據(jù):

這是因為 Excel 默認并不是 UTF-8 編碼,因此要解決這個亂碼問題,可以在對應(yīng)的 CSV 文件寫入 UTF-8 BOM 頭,告知 Excel 通過 UTF-8 編碼打開這個文件:
...
//?寫入?UTF-8?BOM,防止中文亂碼
csvFile.WriteString("\xEF\xBB\xBF")
//?初始化一個?csv?writer,并通過這個?writer?寫入數(shù)據(jù)到?csv?文件
writer?:=?csv.NewWriter(csvFile)
...
再次運行程序,通過 Excel 打開 tutorials.csv,就可以看到正常渲染的數(shù)據(jù)了:

關(guān)于 Excel 文件的讀取和寫入,學(xué)院君就簡單介紹到這里,這里留一個課后作業(yè),參考 encoding/csv 包讀寫 CSV 文件的方式,試著編寫一段使用 encoding/json 包讀寫 JSON 文件的代碼并正常運行起來,看看生成的文件是否符合預(yù)期。
(全文完)
推薦閱讀
站長 polarisxu
自己的原創(chuàng)文章
不限于 Go 技術(shù)
職場和創(chuàng)業(yè)經(jīng)驗
Go語言中文網(wǎng)
每天為你
分享 Go 知識
Go愛好者值得關(guān)注
