Go Web:數據存儲(3)——gob對象序列化

序列化持久存儲gob

本篇文章仍然接前面的文章:內存存儲,主要介紹將博客文章數據序列化持久到文件中。html

encoding/gob包用於編碼器和解碼器之間進行二進制流的數據交換,例如發送端和接收端之間交換數據。也能用來實現對象序列化,並持久保存的功能,而後再須要的時候加載並解碼成原始數據。golang

gob包的用法很簡單,但有必要去了解它的背景知識,見官方手冊:https://golang.org/pkg/encoding/gob/數據結構

下面是序列化到文件中的函數代碼:app

func storeToGob(data interface{}, filename string) {
    buffer := new(bytes.Buffer)
    encoder := gob.NewEncoder(buffer)
    err := encoder.Encode(data)
    if err != nil {
        panic(err)
    }
    err = ioutil.WriteFile(filename, buffer.Bytes(), 0600)
    if err != nil {
        panic(err)
    }
}

其中gob.NewEncoder()函數用來生成一個gob的流編碼器。經過編碼器的Encode()方法,能夠將數據編碼成二進制格式,Encode()方法的參數類型是interface{},因此storeToGob()函數的第一個參數也指定爲此類型能夠將任意數據結構序列化。而後只需將序列化到buffer中的數據寫入到文件中便可。函數

須要注意的是上面使用ioutil.WriteFile()函數會在文件存在時進行截斷,文件不存在時以給定權限(上面給的權限是600)進行文件建立。post

另外,gob不會序列化指針,它會找到指針所指向的數據對象,並對數據對象進行序列化編碼

由於這個函數接受任意類型的數據結構,因此能夠將map類型的PostById和PostByAuthor進行序列化,也能夠將Post類型的單篇文章進行序列化。指針

storeToGob(PostById, "d:/PostById.gob")
storeToGob(PostByAuthor, "d:/PostByAuthor.gob")
storeToGob(post3, "d:/post3.gob")

序列化以後,能夠加載序列化後的文件進行解碼。加載gob文件並解碼二進制數據的函數以下:code

func load(data interface{}, filename string) {
    raw, err := ioutil.ReadFile(filename)
    if err != nil {
        panic(err)
    }
    buffer := bytes.NewBuffer(raw)
    dec := gob.NewDecoder(buffer)
    err = dec.Decode(data)
    if err != nil {
        panic(err)
    }
}

邏輯很簡單,從文件中讀取數據,並解碼後保存到data中。htm

惟一須要注意的是解碼器的解碼方法Decode()的參數雖然是interface{}類型的,但卻要求只能是指針類型。若是傳參時傳遞的是非指針類型,將報錯。

例如,分別解碼前文保存的3個gob文件,並分別保存到對應的數據結構中:

load(&PostById, "d:/PostById.gob")
fmt.Println(PostById[1])
fmt.Println(PostById[2])

load(&PostByAuthor, "d:/PostByAuthor.gob")
for _, post := range PostByAuthor["userA"] {
    fmt.Println(post)
}

var post33 *Post
load(&post33, "d:/post3.gob")
fmt.Println(post33)

注意上面調用load()函數時,傳遞的第一個參數都是指針類型的。post33變量自身就是指針,因此上面load(post33,"d:/post3.gob")也是可行的,但傳遞post33&post33的結果是不同的,以下:

// load(post33, "d:/post3.gob")
{3 Hello 3 userC}

// load(&post33, "d:/post3.gob")
&{3 Hello 3 userC}

如今數據又回到了內存存儲結構上,能夠進行正常的增、刪、改、查等操做。

下面是完整的代碼:

package main

import (
    "bytes"
    "encoding/gob"
    "fmt"
    "io/ioutil"
)

type Post struct {
    Id      int
    Content string
    Author  string
}

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

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

func storeToGob(data interface{}, filename string) {
    buffer := new(bytes.Buffer)
    encoder := gob.NewEncoder(buffer)
    err := encoder.Encode(data)
    if err != nil {
        panic(err)
    }
    err = ioutil.WriteFile(filename, buffer.Bytes(), 0600)
    if err != nil {
        panic(err)
    }
}

func load(data interface{}, filename string) {
    raw, err := ioutil.ReadFile(filename)
    if err != nil {
        panic(err)
    }
    buffer := bytes.NewBuffer(raw)
    dec := gob.NewDecoder(buffer)
    err = dec.Decode(data)
    if err != nil {
        panic(err)
    }
}

func main() {
    PostById = make(map[int]*Post)
    PostByAuthor = 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)

    storeToGob(PostById, "d:/PostById.gob")
    storeToGob(PostByAuthor, "d:/PostByAuthor.gob")
    storeToGob(post3, "d:/post3.gob")

    PostById = map[int]*Post{}
    PostByAuthor = map[string][]*Post{}

    var post33 *Post
    load(&post33, "d:/post3.gob")
    fmt.Println(post33)

    load(&PostById, "d:/PostById.gob")
    fmt.Println(PostById[1])
    fmt.Println(PostById[2])

    load(&PostByAuthor, "d:/PostByAuthor.gob")
    for _, post := range PostByAuthor["userA"] {
        fmt.Println(post)
    }
}
相關文章
相關標籤/搜索