Go Web:數據存儲(2)——CSV文件

存儲到CSV文件中

本文接上一篇:內存存儲html

關於CSV文件的說明,見csv文件格式app

當數據存儲到了內存中,能夠在須要的時候持久化保存到磁盤文件中。好比保存爲csv格式的文件,下一篇再介紹序列化持久到文件中。函數

下面是持久化到csv文件的函數代碼:post

func storeToCsv(filename string, posts map[int]*Post) {
    // 建立文件
    csvFile, err := os.Create(filename)
    if err != nil {
        panic(err)
    }
    defer csvFile.Close()

    // 獲取csv的Writer
    writer := csv.NewWriter(csvFile)

    // 將map中的Post轉換成slice,由於csv的Write須要slice參數
    // 並寫入csv文件
    for _, post := range posts {
        record := []string{strconv.Itoa(post.Id), post.Content, post.Author}
        err1 := writer.Write(record)
        if err1 != nil {
            panic(err1)
        }
    }

    // 確保全部內存數據刷到csv文件
    writer.Flush()
}

這個函數的邏輯很簡單,無需過多的解釋。須要注意的是,os.Create()函數在文件存在時會截斷文件,若有須要,能夠考慮使用追加寫入的相關函數。測試

當須要將保存在內存中的post保存到csv文件時,只需調用該函數,傳遞一個文件名以及PostById做爲參數便可:指針

storeToCsv("d:/a.csv", PostById)

保存以後,如下是a.csv文件的內容:code

2,Hello 2,userB
3,Hello 3,userC
4,Hello 4,userA
1,Hello 1,userA

數據保存到了csv文件,天然須要從csv文件中讀取數據到內存。如下是讀取csv文件的函數:htm

func load(filename string) []*Post {
    // 打開文件
    file, err := os.Open(filename)
    if err != nil {
        panic(err)
    }
    defer file.Close()

    // 獲取csv的reader
    reader := csv.NewReader(file)
    
    // 設置FieldsPerRecord爲-1
    reader.FieldsPerRecord = -1

    // 讀取文件中全部行保存到slice中
    records, err := reader.ReadAll()
    if err != nil {
        panic(err)
    }

    var posts []*Post
    // 將每一行數據保存到內存slice中
    for _, item := range records {
        id, _ := strconv.Atoi(item[0])
        post := &Post{Id: id, Content: item[1], Author: item[2]}
        posts = append(posts, post)
    }
    return posts
}

邏輯也很簡單,惟一須要注意的是FiledsPerRecord=-1blog

  • 設置爲負數表示讀取時每條記錄的字段數量能夠隨意
  • 若是設置爲正數N,則表示每條記錄必須且只讀取N個字段,若是字段少於N,則報錯
  • 若是設置爲0,則表示按照第一條記錄所擁有的字段數量進行讀取剩餘記錄,也就是說每一條記錄的字段數量都必須和第一條記錄相同

這個load()函數返回一個slice,這個slice中保存了全部讀取到的文章指針。內存

s := load("d:/a.csv")

由於使用var PostById map[int]*Postvar PostsByAuthor map[string][]*Post保存一篇篇的文章,迭代此slice便可將slice中的post保存到這兩個map中。

for _, post := range s {
    store(post)
}

而後就能夠從這兩個map中按照Id或者按照Author進行檢索:

fmt.Println(PostById[1])
fmt.Println(PostById[2])
for _, post := range PostsByAuthor["userA"] {
    fmt.Println(post)
}

下面是完整的保存到csv文件以及讀取csv文件的代碼:

package main

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

type Post struct {
    Id      int
    Content string
    Author  string
}

var PostById map[int]*Post
var PostsByAuthor map[string][]*Post

func store(post *Post) {
    PostById[post.Id] = post
    PostsByAuthor[post.Author] = append(PostsByAuthor[post.Author], post)
}

func storeToCsv(filename string, posts map[int]*Post) {
    csvFile, err := os.Create(filename)
    if err != nil {
        panic(err)
    }
    defer csvFile.Close()

    writer := csv.NewWriter(csvFile)

    for _, post := range posts {
        record := []string{strconv.Itoa(post.Id), post.Content, post.Author}
        err1 := writer.Write(record)
        if err1 != nil {
            panic(err1)
        }
    }

    writer.Flush()
}

func load(filename string) []*Post {
    file, err := os.Open(filename)
    if err != nil {
        panic(err)
    }
    defer file.Close()

    reader := csv.NewReader(file)
    reader.FieldsPerRecord = -1
    records, err := reader.ReadAll()
    if err != nil {
        panic(err)
    }

    var posts []*Post
    for _, item := range records {
        id, _ := strconv.Atoi(item[0])
        post := &Post{Id: id, Content: item[1], Author: item[2]}
        posts = append(posts, post)
    }
    return posts
}

func main() {
    PostById = make(map[int]*Post)
    PostsByAuthor = make(map[string][]*Post)

    // 模擬幾篇文章
    post1 := &Post{Id: 1, Content: "Hello 1", Author: "userA"}
    post2 := &Post{Id: 2, Content: "Hello 2", Author: "userB"}
    post3 := &Post{Id: 3, Content: "Hello 3", Author: "userC"}
    post4 := &Post{Id: 4, Content: "Hello 4", Author: "userA"}
    // 存儲到內存中
    store(post1)
    store(post2)
    store(post3)
    store(post4)

    // 將內存中的map容器,保存到csv文件中
    storeToCsv("d:/a.csv", PostById)

    // 爲了測試,此處將已保存在內存中的數據清空
    PostById = map[int]*Post{}
    PostsByAuthor = map[string][]*Post{}

    // 下面是加載csv文件
    s := load("d:/a.csv")
    for _, post := range s {
        store(post)
    }

    // 檢索
    fmt.Println(PostById[1])
    fmt.Println(PostById[2])
    for _, post := range PostsByAuthor["userA"] {
        fmt.Println(post)
    }
    for _, post := range PostsByAuthor["userC"] {
        fmt.Println(post)
    }
}

運行結果:

&{1 Hello 1 userA}
&{2 Hello 2 userB}
&{1 Hello 1 userA}
&{4 Hello 4 userA}
&{3 Hello 3 userC}
相關文章
相關標籤/搜索