Go 數(shù)據(jù)存儲篇(二):通過 JSON 格式存取文本數(shù)據(jù)

內(nèi)存存儲性能雖好,但是無法持久化存儲,并且容量也是有限的,要將大塊數(shù)據(jù)永久保存起來,還是需要借助文件系統(tǒng)和數(shù)據(jù)庫。我們先來看文件存儲。
存儲數(shù)據(jù)到文件系統(tǒng)有兩種方式,一種是文本格式,比如 CSV、JSON 格式文件,一種是二進(jìn)制格式,比如 Gob。接下來我們通過三篇教程的篇幅分別進(jìn)行演示。
首先來看如何通過 JSON 格式保存數(shù)據(jù)到文件。
我們在上篇教程中已經(jīng)演示過如何在內(nèi)存中通過 Go 提供的數(shù)據(jù)類型處理數(shù)據(jù)。如果要將處理后的數(shù)據(jù)保存到文件系統(tǒng),對于基本類型而言(數(shù)字、字符串)直接寫入文件即可,而對于數(shù)組、切片、字典、結(jié)構(gòu)體這種復(fù)合類型,Go 語言官方?jīng)]有像 PHP 那樣直接提供序列化函數(shù),我們可以通過 JSON 編碼將其轉(zhuǎn)化為 JSON 格式字符串寫入文件(序列化),后面需要用到它們從文件中讀取后,可以通過 JSON 解碼再將其轉(zhuǎn)化為原來的數(shù)據(jù)類型(反序列化)。
下面,我們編寫一段示例代碼 json.go 進(jìn)行演示:
package?main
import?(
????"encoding/json"
????"fmt"
????"io/ioutil"
)
//?存放文章信息的?Post?結(jié)構(gòu)體
type?Book?struct?{
????Id?int?`json:"id"`
????Title?string?`json:"title"`
????Summary?string?`json:"summary"`
????Author?string?`json:"author"`
}
func?main()??{
????//?初始化一個字典類型變量
????var?books?map[int]*Book?=?make(map[int]*Book)
????book1?:=?Book{Id:?1,?Title:?"Go?Web?編程",?Summary:?"Go?Web?編程入門指南",?Author:?"學(xué)院君"}
????books[book1.Id]?=?&book1
????//?通過?JSON?序列化字典數(shù)據(jù)
????data,?_?:=?json.Marshal(books)
????//?將?JSON?格式數(shù)據(jù)寫入當(dāng)前目錄下的d?books?文件(文件不存在會自動創(chuàng)建)
????err?:=?ioutil.WriteFile("books",?data,?0644)
????if?err?!=?nil?{
????????panic(err)
????}
????//?從文件?books?中讀取數(shù)據(jù)
????dataEncoded,?_?=?ioutil.ReadFile("books")
????//?將讀取到的數(shù)據(jù)通過?JSON?解碼反序列化為原來的數(shù)據(jù)類型
????var?booksDecoded?map[int]*Book
????json.Unmarshal(dataEncoded,?&booksDecoded)
????fmt.Printf("%#v",?booksDecoded[book1.Id])
}
執(zhí)行上述代碼,輸出結(jié)果如下,說明 JSON 解碼成功:

此外,我們還可以在當(dāng)前目錄下看到新生成了一個 books 文件,文件內(nèi)容如下:
{"1":{"id":1,"title":"Go?Web?編程","summary":"Go?Web?編程入門指南","author":"學(xué)院君"}}
由此可見,我們已經(jīng)成功通過 JSON 實現(xiàn)了文本格式數(shù)據(jù)的序列化和反序列化。
另外,讀寫文件除了使用 ioutil 包之外,還可以使用 os 包提供的函數(shù),前者更加方便,后者則更加底層,支持的操作和功能更多:
package?main
import?(
????"encoding/json"
????"fmt"
????"os"
)
//?存放文章信息的?Post?結(jié)構(gòu)體
type?Book?struct?{
????Id?int?`json:"id"`
????Title?string?`json:"title"`
????Summary?string?`json:"summary"`
????Author?string?`json:"author"`
}
func?main()??{
????//?初始化一個字典類型變量
????var?books?map[int]*Book?=?make(map[int]*Book)
????book1?:=?Book{Id:?1,?Title:?"Go?Web?編程",?Summary:?"Go?Web?編程入門指南",?Author:?"學(xué)院君"}
????books[book1.Id]?=?&book1
????//?通過?JSON?序列化字典數(shù)據(jù)
????data,?_?:=?json.Marshal(books)
????//?將?JSON?格式數(shù)據(jù)寫入當(dāng)前目錄下的?books?文件
????//?err?:=?ioutil.WriteFile("books",?data,?0644)
????file1,?_?:=?os.Create("books")
????defer?file1.Close()
????_,?err?:=?file1.Write(data)
????if?err?!=?nil?{
????????panic(err)
????}
????//?從文件?books?中讀取數(shù)據(jù)
????//dataEncoded,?_?=?ioutil.ReadFile("books")
????file2,?_?:=?os.Open("books")
????defer?file2.Close()
????dataEncoded?:=?make([]byte,?len(data))
????file2.Read(dataEncoded)
????//?將讀取到的數(shù)據(jù)通過?JSON?解碼反序列化為原來的數(shù)據(jù)類型
????var?booksDecoded?map[int]*Book
????json.Unmarshal(dataEncoded,?&booksDecoded)
????fmt.Printf("%#v",?booksDecoded[book1.Id])
}
注:可將兩種文件讀寫方式類比為 PHP 中的 file_get_contents/file_put_contents 函數(shù)與通過 fopen 函數(shù)獲取文件句柄進(jìn)行文件讀寫操作。
運行上述代碼,結(jié)果和之前完全一致:

(全文完)
推薦閱讀
站長 polarisxu
自己的原創(chuàng)文章
不限于 Go 技術(shù)
職場和創(chuàng)業(yè)經(jīng)驗
Go語言中文網(wǎng)
每天為你
分享 Go 知識
Go愛好者值得關(guān)注
