18 Go的Gob
作者:mmseoamin日期:2023-12-11

概述

        在上一节的内容中,我们介绍了Go的文件操作,包括:读取文件、写入文件、删除文件、目录操作、遍历目录下文件等。在本节中,我们将介绍Go的Gob。Gob是Go语言中的一种序列化二进制格式,用于在Go语言之间进行数据传输和持久化存储,具有高效和紧凑的特点。Gob编码器将Go语言中的数据结构转换为二进制格式,而Gob解码器则将二进制格式的数据解码为Go语言中的数据结构。Gob使用可扩展的编码方案,可以处理任意类型的数据结构,包括:数组、切片、映射、嵌套结构等。

Gob简介

        Gob是专门为Go语言设计,用于序列化和反序列化数据的一种格式,位于"encoding/gob"包中。

        Gob的特点在于它是一种自描述的二进制格式,包含所有类型的描述,并且可以由Go语言解码,而无需了解文件的内容。只有可导出的字段会被编码,零值会被忽略。在解码结构体的时候,只有同时匹配名称和可兼容类型的字段才会被解码。当源数据类型增加新字段后,Gob解码仍然可以正常工作,解码客户端会继续识别以前存在的字段。

        注意:Gob并不是一种不同于Go的语言,而是在编码和解码过程中用到了Go的反射。它是一种二进制格式,不像Json或XML那样是文本格式。

Gob编码

        Gob编码器可以将Go语言中的数据结构转换为二进制格式,以便在网络传输或持久化存储时使用。下面是一些常用的编码函数。

        NewEncoder(io.Writer) Encoder:创建一个新的编码器,用于将Go语言的数据结构编码为二进制格式。参数是一个io.Writer,编码的数据将写入该Writer中。

        Encode(interface{}) error:使用指定的编码器将一个Go语言的数据结构编码为二进制格式,并写入指定的Writer中。参数是一个实现了interface{}类型的值,该函数将自动为该值编码。

        GobEncode(interface{}) ([]byte, error):将一个Go语言的数据结构编码为Gob格式的字节切片,参数是一个实现了interface{}类型的值,该函数将自动为该值编码。

        在下面的示例代码中,我们首先定义了一个Person结构体,它具有Name和Age两个字段。然后,我们创建了一个Person对象person。接下来,我们创建了一个文件person.gob,用于写入编码后的数据。最后,我们创建了一个编码器encoder,它将Person对象编码为Gob格式并写入文件。注意:Person结构体中的属性名必须为大写,否则编码时会出错,提示:“gob: type main.Person has no exported fields”。

package main
import "os"
import "fmt"
import "encoding/gob"
type Person struct {
    Name string
    Age  int
}
func main() {
    // 创建一个Person对象
    person := Person{"Mike", 18}
    // 创建文件,用于写入编码后的数据
    file, err := os.Create("person.gob")
    if err != nil {
        fmt.Println("Create failed:", err)
        return
    }
    defer file.Close()
    // 创建编码器,将Person对象编码为GOB格式并写入文件
    encoder := gob.NewEncoder(file)
    err = encoder.Encode(person)
    if err != nil {
        fmt.Println("Encode failed:", err)
        return
    }
    fmt.Println("Encode success")
}

Gob解码

        Gob解码器可以将二进制格式的数据解码为Go语言中的数据结构,下面是一些常用的解码函数。

        NewDecoder(io.Reader) Decoder:创建一个新的解码器,用于从二进制格式的数据中解码出Go语言的数据结构。参数是一个io.Reader,解码的数据将从该Reader中读取。

        Decode(interface{}) error:使用指定的解码器从二进制格式的数据中解码出一个Go语言的数据结构,并存储在指定的值中。参数是一个实现了interface{}类型的值,该函数将自动为该值解码。

        GobDecode([]byte, interface{}) error:从一个Gob格式的字节切片中解码出一个Go语言的数据结构,并存储在指定的值中。参数是一个实现了interface{}类型的值,该函数将自动为该值解码。

        在下面的示例代码中,我们首先定义了一个Person结构体,它具有Name和Age两个字段。接下来,我们读取了上述编码好的文件person.gob,用于从文件中解码数据。最后,我们创建了一个解码器decoder,用于从文件中读取Gob格式的数据,并解码存入到person对象中。

package main
import "os"
import "fmt"
import "encoding/gob"
type Person struct {
    Name string
    Age  int
}
func main() {
    person := Person{}
     // 创建一个文件用于写入编码后的数据
     file, err := os.Open("person.gob")
     if err != nil {
         fmt.Println("Open failed:", err)
         return
     }
     defer file.Close()
     // 创建解码器,从文件中解码GOB格式数据并存入Person对象
     decoder := gob.NewDecoder(file)
     err = decoder.Decode(&person)
     if err != nil {
         fmt.Println("Decode failed:", err)
         return
     }
     // 输出:Decode success: {Mike 18}
     fmt.Println("Decode success:", person)
}

        除了可以将数据结构编码到文件中,还可以将数据结构编码到字节切片中,并从字节切片中解码。

        在下面的示例代码中,我们首先定义了一个Person结构体。然后,我们创建了一个缓冲区buf,用于存储编码后的数据。接下来,我们创建了一个编码器encoder,它将数据person编码为gob格式并写入缓冲区buf。最后,我们创建了一个解码器decoder,它从缓冲区中读取编码后的数据并解码为Person对象decodedPerson。

package main
import "fmt"
import "bytes"
import "encoding/gob"
type Person struct {
    Name string
    Age  int
}
  
func main() {
    // 创建一个缓冲区,用于编码数据
    var buf bytes.Buffer
    // 创建一个编码器,将数据编码为gob格式并写入缓冲区
    encoder := gob.NewEncoder(&buf)
    // 创建一个Person对象
    person := Person{"Mike", 18}
    // 将Person对象编码为gob格式并写入缓冲区
    err := encoder.Encode(person)
    if err != nil {
        fmt.Println("Encode failed:", err)
        return
    }
    // 从缓冲区中读取编码后的数据
    decodedPerson := Person{}
    decoder := gob.NewDecoder(&buf)
    err = decoder.Decode(&decodedPerson)
    if err != nil {
        fmt.Println("Decode failed:", err)
        return
    }
    // 输出:Decoded data: {Mike 18}
    fmt.Println("Decoded data:", decodedPerson)
}