概述
在上一节的内容中,我们介绍了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)
}