## 使用CSV格式化數據
CSV是操作數據的常用格式。將CSV文件導入或導出到Excel中亦是很常見的操作。Go的CSV包提供了數據操作接口,因此可以輕松地將數據寫入緩沖區,標準輸出,文件或socket。本節將展示將數據導入和導出CSV格式的一些常用方法。
### 實踐
1. 建立read_csv.go:
```
package csvformat
import (
"bytes"
"encoding/csv"
"fmt"
"io"
"strconv"
)
// Movie用來存儲CSV解析后的內容
type Movie struct {
Title string
Director string
Year int
}
// ReadCSV 展示了如何處理CSV
// 接收的參數通過io.Reader傳入
func ReadCSV(b io.Reader) ([]Movie, error) {
//返回的是csv.Reader
r := csv.NewReader(b)
// 分隔符和注釋是csv.Reader結構體中的字段
r.Comma = ';'
r.Comment = '-'
var movies []Movie
// 讀取并返回一個字符串切片和錯誤信息
// 我們也可以將其用于字典鍵或其他形式的查找
// 此處忽略了返回的切片 目的是跳過csv首行標題
_, err := r.Read()
if err != nil && err != io.EOF {
return nil, err
}
// 循環直到全部處理完畢
for {
record, err := r.Read()
if err == io.EOF {
break
} else if err != nil {
return nil, err
}
year, err := strconv.ParseInt(record[2], 10, 64)
if err != nil {
return nil, err
}
m := Movie{record[0], record[1], int(year)}
movies = append(movies, m)
}
return movies, nil
}
// AddMoviesFromText 將字符串按 CSV 格式解析
func AddMoviesFromText() error {
in := `
- first our headers
movie title;director;year released
- then some data
Guardians of the Galaxy Vol. 2;James Gunn;2017
Star Wars: Episode VIII;Rian Johnson;2017
`
b := bytes.NewBufferString(in)
m, err := ReadCSV(b)
if err != nil {
return err
}
fmt.Printf("%#v\n", m)
return nil
}
```
2. 建立 write_csv.go:
```
package csvformat
import (
"bytes"
"encoding/csv"
"io"
"os"
)
// 結構體Book有Author和Title兩個字段
type Book struct {
Author string
Title string
}
// Books是Book的切片類型
type Books []Book
// ToCSV將Books寫入傳進來的 io.Writer
// 返回任何可能發生的錯誤
func (books *Books) ToCSV(w io.Writer) error {
n := csv.NewWriter(w)
err := n.Write([]string{"Author", "Title"})
if err != nil {
return err
}
for _, book := range *books {
err := n.Write([]string{book.Author, book.Title})
if err != nil {
return err
}
}
n.Flush()
return n.Error()
}
// WriteCSVOutput 初始化Books并調用ToCSV
// 并寫入到標準輸出
func WriteCSVOutput() error {
b := Books{
Book{
Author: "F Scott Fitzgerald",
Title: "The Great Gatsby",
},
Book{
Author: "J D Salinger",
Title: "The Catcher in the Rye",
},
}
return b.ToCSV(os.Stdout)
}
// WriteCSVBuffer 初始化Books并調用ToCSV
// 并寫入到bytes.Buffers
func WriteCSVBuffer() (*bytes.Buffer, error) {
b := Books{
Book{
Author: "F Scott Fitzgerald",
Title: "The Great Gatsby",
},
Book{
Author: "J D Salinger",
Title: "The Catcher in the Rye",
},
}
w := &bytes.Buffer{}
err := b.ToCSV(w)
return w, err
}
```
3. 建立main.go:
```
import (
"fmt"
"github.com/agtorre/go-cookbook/chapter1/csvformat"
)
func main() {
if err := csvformat.AddMoviesFromText(); err != nil {
panic(err)
}
if err := csvformat.WriteCSVOutput(); err != nil {
panic(err)
}
buffer, err := csvformat.WriteCSVBuffer()
if err != nil {
panic(err)
}
fmt.Println("Buffer = ", buffer.String())
}
```
4. 運行main.go,這會輸出:
```
[]csvformat.Movie{csvformat.Movie{Title:"Guardians of the Galaxy Vol. 2", Director:"James Gunn", Year:2017}, csvformat.Movie{Title:"Star Wars: Episode VIII", Director:"Rian Johnson", Year:2017}}
Author,Title
F Scott Fitzgerald,The Great Gatsby
J D Salinger,The Catcher in the Rye
Buffer = Author,Title
F Scott Fitzgerald,The Great Gatsby
J D Salinger,The Catcher in the Rye
```
### 說明
為了探索CSV格式操作,我們首先將數據表示為結構。在Go中將數據格式化為結構非常有用,這會使目標封裝和編碼等變得相對簡單。 我們的示例中使用自定義的Movie結構。它所屬的函數接收io.Reader接口作為參數以使CSV數據輸入時更加靈活——文件或緩沖區都可以輸入進來。接下來,我們使用傳入的數據來創建并填充Movie結構,我們還向CSV解析器添加了 ; 作為分隔符 - 作為注釋行。
接下來,我們以類似的方式探索CSV格式的寫入操作,我們初始化一系列Books,然后將CSV格式的特定book寫入io.Writer接口,同樣的,目標可以是文件,標準輸出或緩沖區。
CSV包是一個很棒的例子,它說明了為什么你需要考慮要將Go中的數據流視為實現通用接口。通過細微的調整,我們可以輕松更改數據的來源和目的地,同時不影響操作CSV數據,并且無需使用過多的內存或時間。例如,可以一次從一個數據流中讀取一個記錄,并以循環的形式將修改的格式寫入單獨的流。這樣做不會占用大量內存或處理器。
稍后,在探索數據管道和工作池時,你將看到如何組合這些想法以及如何并行處理這些流。
* * * *
學識淺薄,錯誤在所難免。歡迎在群中就本書提出修改意見,以饗后來者,長風拜謝。
Golang中國(211938256)
beego實戰(258969317)
Go實踐(386056972)
- 前言
- 第一章 I/O和文件系統
- 常見 I/O 接口
- 使用bytes和strings包
- 操作文件夾和文件
- 使用CSV格式化數據
- 操作臨時文件
- 使用 text/template和HTML/templates包
- 第二章 命令行工具
- 解析命令行flag標識
- 解析命令行參數
- 讀取和設置環境變量
- 操作TOML,YAML和JSON配置文件
- 操做Unix系統下的pipe管道
- 處理信號量
- ANSI命令行著色
- 第三章 數據類型轉換和解析
- 數據類型和接口轉換
- 使用math包和math/big包處理數字類型
- 貨幣轉換和float64注意事項
- 使用指針和SQL Null類型進行編碼和解碼
- 對Go數據編碼和解碼
- Go中的結構體標簽和反射
- 通過閉包實現集合操作
- 第四章 錯誤處理
- 錯誤接口
- 使用第三方errors包
- 使用log包記錄錯誤
- 結構化日志記錄
- 使用context包進行日志記錄
- 使用包級全局變量
- 處理恐慌
- 第五章 數據存儲
- 使用database/sql包操作MySQL
- 執行數據庫事務接口
- SQL的連接池速率限制和超時
- 操作Redis
- 操作MongoDB
- 創建存儲接口以實現數據可移植性
- 第六章 Web客戶端和APIs
- 使用http.Client
- 調用REST API
- 并發操作客戶端請求
- 使用OAuth2
- 實現OAuth2令牌存儲接口
- 封裝http請求客戶端
- 理解GRPC的使用
- 第七章 網絡服務
- 處理Web請求
- 使用閉包進行狀態處理
- 請求參數驗證
- 內容渲染
- 使用中間件
- 構建反向代理
- 將GRPC導出為JSON API
- 第八章 測試
- 使用標準庫進行模擬
- 使用Mockgen包
- 使用表驅動測試
- 使用第三方測試工具
- 模糊測試
- 行為驅動測試
- 第九章 并發和并行
- 第十章 分布式系統
- 第十一章 響應式編程和數據流
- 第十二章 無服務器編程
- 第十三章 性能改進