CSV是操作資料的常用格式。將CSV檔案匯入或匯出到Excel中亦是很常見的操作。Go的CSV包提供了資料操作介面,因此可以輕鬆地將資料寫入緩衝區,標準輸出,檔案或socket。本節將展示將資料匯入和匯出CSV格式的一些常用方法。
參考:go語言中文文件:www.topgoer.com
實踐1.建立read_csv.go:
package csvformatimport ( "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 headersmovie title;director;year released- then some dataGuardians of the Galaxy Vol. 2;James Gunn;2017Star 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 csvformatimport ( "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.Buffersfunc 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,TitleF Scott Fitzgerald,The Great GatsbyJ D Salinger,The Catcher in the RyeBuffer = Author,TitleF Scott Fitzgerald,The Great GatsbyJ D Salinger,The Catcher in the Rye
說明為了探索CSV格式操作,我們首先將資料表示為結構。在Go中將資料格式化為結構非常有用,這會使目標封裝和編碼等變得相對簡單。 我們的示例中使用自定義的Movie結構。它所屬的函式接收io.Reader介面作為引數以使CSV資料輸入時更加靈活——檔案或緩衝區都可以輸入進來。接下來,我們使用傳入的資料來建立並填充Movie結構,我們還向CSV解析器添加了 ; 作為分隔符 - 作為註釋行。
接下來,我們以類似的方式探索CSV格式的寫入操作,我們初始化一系列Books,然後將CSV格式的特定book寫入io.Writer介面,同樣的,目標可以是檔案,標準輸出或緩衝區。
CSV包是一個很棒的例子,它說明了為什麼你需要考慮要將Go中的資料流視為實現通用介面。透過細微的調整,我們可以輕鬆更改資料的來源和目的地,同時不影響操作CSV資料,並且無需使用過多的記憶體或時間。例如,可以一次從一個數據流中讀取一個記錄,並以迴圈的形式將修改的格式寫入單獨的流。這樣做不會佔用大量記憶體或處理器。
稍後,在探索資料管道和工作池時,你將看到如何組合這些想法以及如何並行處理這些流。
最新評論