本文小编为大家详细介绍“Golang怎么使用gob实现结构体的序列化”,内容详细,步骤清晰,细节处理妥当,希望这篇“Golang怎么使用gob实现结构体的序列化”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。
Golang有自己的序列化格式,称为gob。使用gob可以对结构进行编码和解码。你可以使用其他格式,如JSON, XML, protobuff等,具体选择要根据实际需求,但当接收和发送都为Golang,我建议使用Go的gob格式。
Gob简介
gob在kg/encoding/gob包中:
gob流是自描述的,这意味着我们不需要创建单独的文件来解释(使用protobuff格式需要创建文件)
gob流中的每个数据项之前都有其类型说明(一些预定义的类型)
Gob包很简单,仅包括8个函数和5个类型:
func Register(value interface{})
func RegisterName(name string, value interface{})
type CommonType
type Decoder
func NewDecoder(r io.Reader) *Decoder
func (dec *Decoder) Decode(e interface{}) error
func (dec *Decoder) DecodeValue(v reflect.Value) error
type Encoder
func NewEncoder(w io.Writer) *Encoder
func (enc *Encoder) Encode(e interface{}) error
func (enc *Encoder) EncodeValue(value reflect.Value) error
type GobDecoder
type GobEncoder
单个对象序列化
首先定义student结构体,包括两个字段Name和Age.
使用gob.NewEncoder和gob.NewDecoder方法,接收io.Writer 和 io.Reader 对象,用于读写文件:
package main
import (
"fmt"
"os"
"encoding/gob"
)
type Student struct {
Name string
Age int32
}
func main() {
fmt.Println("Gob Example")
student := Student{"Ketan Parmar",35}
err := writeGob("./student.gob",student)
if err != nil{
fmt.Println(err)
}
var studentRead = new (Student)
err = readGob("./student.gob",studentRead)
if err != nil {
fmt.Println(err)
} else {
fmt.Println(studentRead.Name, " ", studentRead.Age)
}
}
func writeGob(filePath string,object interface{}) error {
file, err := os.Create(filePath)
if err == nil {
encoder := gob.NewEncoder(file)
encoder.Encode(object)
}
file.Close()
return err
}
func readGob(filePath string,object interface{}) error {
file, err := os.Open(filePath)
if err == nil {
decoder := gob.NewDecoder(file)
err = decoder.Decode(object)
}
file.Close()
return err
}
列表数据序列化
首先创建student结构体数组或slice,然后填充数据。下面示例无需修改readGob和writeGob函数:
package main
import (
"fmt"
"os"
"encoding/gob"
)
type Student struct {
Name string
Age int32
}
type Students []Student
func main() {
fmt.Println("Gob Example")
students := Students{}
students = append(students,Student{"Student 1",20})
students = append(students,Student{"Student 2",25})
students = append(students,Student{"Student 3",30})
err := writeGob("./student.gob",students)
if err != nil{
fmt.Println(err)
}
var studentRead = new (Students)
err = readGob("./student.gob",studentRead)
if err != nil {
fmt.Println(err)
} else {
for _,v := range *studentRead{
fmt.Println(v.Name, " ", v.Age)
}
}
}
上面两个示例主要使用了NewEncoder 和 NewDecoder,接下来看看其他函数:Register, Encode, EncodeValue, Decode 和 DecodeValue。
Encode 和 Decode 函数主要用于网络应用程序,方法签名如下:
func (dec *Decoder) Decode(e interface{}) error
func (enc *Encoder) Encode(e interface{}) error
简单编码示例
package main
import (
"fmt"
"encoding/gob"
"bytes"
)
type Student struct {
Name string
Age int32
}
func main() {
fmt.Println("Gob Example")
studentEncode := Student{Name:"Ketan",Age:30}
var b bytes.Buffer
e := gob.NewEncoder(&b)
if err := e.Encode(studentEncode); err != nil {
panic(err)
}
fmt.Println("Encoded Struct ", b)
var studentDecode Student
d := gob.NewDecoder(&b)
if err := d.Decode(&studentDecode); err != nil {
panic(err)
}
fmt.Println("Decoded Struct ", studentDecode.Name," ",studentDecode.Age)
}
上面示例把student结构序列化、反序列化。序列化后存储在字节buffer变量b中,先可以使用b在网络中传输。要解码仅需要创建相同结构对象并提供其地址。studentDecode变量获得解码的内容。
编码在TCP连接中使用
TCP客户端:打开连接使用gob.Encoder方法编码数据进行传输:
package main
import (
"fmt"
"encoding/gob"
"net"
"log"
)
type Student struct {
Name string
Age int32
}
func main() {
fmt.Println("Client")
//create structure object
studentEncode := Student{Name:"Ketan",Age:30}
fmt.Println("start client");
// dial TCP connection
conn, err := net.Dial("tcp", "localhost:8080")
if err != nil {
log.Fatal("Connection error", err)
}
//Create encoder object, We are passing connection object in Encoder
encoder := gob.NewEncoder(conn)
// Encode Structure, IT will pass student object over TCP connection
encoder.Encode(studentEncode)
// close connection
conn.Close()
fmt.Println("done");
}
TCP Server: 监听8080端口,在go协程中处理所有客户端,使用gob.Decoder方法解码student结构体并输出:
package main
import (
"fmt"
"net"
"encoding/gob"
)
type Student struct {
Name string
Age int32
}
func handleConnection(conn net.Conn) {
// create new decoder object and provide connection
dec := gob.NewDecoder(conn)
// create blank student object
p := &Student{}
// decode serialize data
dec.Decode(p)
// print
fmt.Println("Hello ",p.Name,", Your Age is ",p.Age);
// close connection for that client
conn.Close()
}
func main() {
fmt.Println("Server")
// start TCP server and listen on port 8080
ln, err := net.Listen("tcp", ":8080")
if err != nil {
// handle error
panic(err)
}
for {
// this blocks until connection or error
conn, err := ln.Accept()
if err != nil {
// handle error
continue
}
// a goroutine handles conn so that the loop can accept other connections
go handleConnection(conn)
}
}
上文中没有实现序列化,本文给出golang-ttl-map实现:
func (h *Heap) append(data Data) (err error) {
h.fileMx.Lock()
defer h.fileMx.Unlock()
// 打开文件
var file *os.File
file, err = os.OpenFile(h.filePath, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0755)
if err != nil {
return
}
defer func() {
_ = file.Sync()
}()
defer func() {
_ = file.Close()
}()
// 定义buffer
var buf bytes.Buffer
enc := gob.NewEncoder(&buf)
// 序列化
err = enc.Encode(data)
if err != nil {
return
}
bs := buf.Bytes()
bs = append(bs, '
')
// 写入文件
_, err = file.Write(bs)
if err != nil {
return
}
return
}