文件存储(一):通过 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 解码成功:

-w859

此外,我们还可以在当前目录下看到新生成了一个 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 函数获取文件句柄进行文件读写操作。

运行上述代码,结果和之前完全一致:

-w816


点赞 取消点赞 收藏 取消收藏

<< 上一篇: 基于内存存储实现数据增删改查功能

>> 下一篇: 文件存储(二):通过 CSV 格式读写文本数据