文件存储(一):通过 JSON 格式序列化文本数据
内存存储性能虽好,但是无法持久化存储,并且容量也是有限的,要将大块数据永久保存起来,还是需要借助文件系统和数据库。我们先来看文件存储。
存储数据到文件系统有两种方式,一种是文本格式,比如 CSV、JSON 格式文件,一种是二进制格式,比如 Gob。接下来我们通过三篇教程的篇幅分别进行演示。
首先来看如何通过 JSON 格式保存数据到文件。
我们在上篇教程中已经演示过如何在内存中通过 Go 提供的数据类型处理数据。如果要将处理后的数据保存到文件系统,对于基本类型而言(数字、字符串)直接写入文件即可,而对于数组、切片、字典、结构体这种复合类型,Go 语言官方没有像 PHP 那样直接提供序列化函数,我们可以通过 JSON 编码将其转化为 JSON 格式字符串写入文件(序列化),后面需要用到它们从文件中读取后,可以通过 JSON 解码再将其转化为原来的数据类型(反序列化)。
下面,我们编写一段示例代码 json.go
进行演示:
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
)
// 存放文章信息的 Post 结构体
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: "学院君"}
books[book1.Id] = &book1
// 通过 JSON 序列化字典数据
data, _ := json.Marshal(books)
// 将 JSON 格式数据写入当前目录下的 books 文件(文件不存在会自动创建)
err := ioutil.WriteFile("books", data, 0644)
if err != nil {
panic(err)
}
// 从文件 books 中读取数据
dataEncoded, _ := ioutil.ReadFile("books")
// 将读取到的数据通过 JSON 解码反序列化为原来的数据类型
var booksDecoded map[int]*Book
json.Unmarshal(dataEncoded, &booksDecoded)
fmt.Printf("%#v", booksDecoded[book1.Id])
}
执行上述代码,输出结果如下,说明 JSON 解码成功:
此外,我们还可以在当前目录下看到新生成了一个 books
文件,文件内容如下:
{"1":{"id":1,"title":"Go Web 编程","summary":"Go Web 编程入门指南","author":"学院君"}}
由此可见,我们已经成功通过 JSON 实现了文本格式数据的序列化和反序列化。
另外,读写文件除了使用 ioutil 包之外,还可以使用 os 包提供的函数,前者更加方便,后者则更加底层,支持的操作和功能更多:
package main
import (
"encoding/json"
"fmt"
"os"
)
// 存放文章信息的 Post 结构体
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: "学院君"}
books[book1.Id] = &book1
// 通过 JSON 序列化字典数据
data, _ := json.Marshal(books)
// 将 JSON 格式数据写入当前目录下的 books 文件
// err := ioutil.WriteFile("books", data, 0644)
file1, _ := os.Create("books")
defer file1.Close()
_, err := file1.Write(data)
if err != nil {
panic(err)
}
// 从文件 books 中读取数据
//dataEncoded, _ = ioutil.ReadFile("books")
file2, _ := os.Open("books")
defer file2.Close()
dataEncoded := make([]byte, len(data))
file2.Read(dataEncoded)
// 将读取到的数据通过 JSON 解码反序列化为原来的数据类型
var booksDecoded map[int]*Book
json.Unmarshal(dataEncoded, &booksDecoded)
fmt.Printf("%#v", booksDecoded[book1.Id])
}
注:可将两种文件读写方式类比为 PHP 中的 file_get_contents/file_put_contents 函数与通过 fopen 函数获取文件句柄进行文件读写操作。
运行上述代码,结果和之前完全一致:
4 Comments
json.go 33行错误 = 应该改成 := 吧
嗯 是的 感谢反馈 已修正
”将 JSON 格式数据写入当前目录下的d books 文件“ 多了一个d
感谢反馈,已修正