Golang使用gob實(shí)現(xiàn)結(jié)構(gòu)體的序列化過程詳解
Golang有自己的序列化格式,稱為gob。使用gob可以對(duì)結(jié)構(gòu)進(jìn)行編碼和解碼。你可以使用其他格式,如JSON, XML, protobuff等,具體選擇要根據(jù)實(shí)際需求,但當(dāng)接收和發(fā)送都為Golang,我建議使用Go的gob格式。
Gob簡(jiǎn)介
gob在kg/encoding/gob包中:
- gob流是自描述的,這意味著我們不需要?jiǎng)?chuàng)建單獨(dú)的文件來解釋(使用protobuff格式需要?jiǎng)?chuàng)建文件)
- gob流中的每個(gè)數(shù)據(jù)項(xiàng)之前都有其類型說明(一些預(yù)定義的類型)
Gob包很簡(jiǎn)單,僅包括8個(gè)函數(shù)和5個(gè)類型:
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
單個(gè)對(duì)象序列化
首先定義student結(jié)構(gòu)體,包括兩個(gè)字段Name和Age.
使用gob.NewEncoder和gob.NewDecoder方法,接收io.Writer 和 io.Reader 對(duì)象,用于讀寫文件:
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, "\t", 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
}
列表數(shù)據(jù)序列化
首先創(chuàng)建student結(jié)構(gòu)體數(shù)組或slice,然后填充數(shù)據(jù)。下面示例無需修改readGob和writeGob函數(shù):
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, "\t", v.Age)
}
}
}
上面兩個(gè)示例主要使用了NewEncoder 和 NewDecoder,接下來看看其他函數(shù):Register, Encode, EncodeValue, Decode 和 DecodeValue。
Encode 和 Decode 函數(shù)主要用于網(wǎng)絡(luò)應(yīng)用程序,方法簽名如下:
func (dec *Decoder) Decode(e interface{}) error
func (enc *Encoder) Encode(e interface{}) error
簡(jiǎn)單編碼示例
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,"\t",studentDecode.Age)
}
上面示例把student結(jié)構(gòu)序列化、反序列化。序列化后存儲(chǔ)在字節(jié)buffer變量b中,先可以使用b在網(wǎng)絡(luò)中傳輸。要解碼僅需要?jiǎng)?chuàng)建相同結(jié)構(gòu)對(duì)象并提供其地址。studentDecode變量獲得解碼的內(nèi)容。
編碼在TCP連接中使用
TCP客戶端:打開連接使用gob.Encoder方法編碼數(shù)據(jù)進(jìn)行傳輸:
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: 監(jiān)聽8080端口,在go協(xié)程中處理所有客戶端,使用gob.Decoder方法解碼student結(jié)構(gòu)體并輸出:
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)
}
}
上文中沒有實(shí)現(xiàn)序列化,本文給出golang-ttl-map實(shí)現(xiàn):
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, '\n')
// 寫入文件
_, err = file.Write(bs)
if err != nil {
return
}
return
}
到此這篇關(guān)于Golang使用gob實(shí)現(xiàn)結(jié)構(gòu)體的序列化過程詳解的文章就介紹到這了,更多相關(guān)Golang結(jié)構(gòu)體序列化內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Go?runtime?調(diào)度器之系統(tǒng)調(diào)用引起的搶占
本文解析了在Go語言中,當(dāng)goroutine執(zhí)行的系統(tǒng)調(diào)用時(shí)間過長(zhǎng)時(shí),系統(tǒng)如何通過監(jiān)控和搶占機(jī)制來處理,以維持運(yùn)行效率和資源分配的平衡,通過具體的示例和流程圖,詳細(xì)展示了系統(tǒng)調(diào)用過程中的搶占操作,感興趣的朋友跟隨小編一起看看吧2024-09-09
Golang 模塊引入及表格讀寫業(yè)務(wù)快速實(shí)現(xiàn)示例
這篇文章主要為大家介紹了Golang模塊引入及表格讀寫業(yè)務(wù)的快速實(shí)現(xiàn)示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-07-07
golang 40行代碼實(shí)現(xiàn)通用協(xié)程池
golang協(xié)程機(jī)制很方便的解決了并發(fā)編程的問題,但是協(xié)程并不是沒有開銷的,所以也需要適當(dāng)限制一下數(shù)量。這篇文章主要介紹了golang 40行代碼實(shí)現(xiàn)通用協(xié)程池,需要的朋友可以參考下2018-08-08
Go語言中init函數(shù)和defer延遲調(diào)用關(guān)鍵詞詳解
這篇文章主要介紹了Go語言中init函數(shù)和defer延遲調(diào)用關(guān)鍵詞,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-03-03
一文教你如何快速學(xué)會(huì)Go的切片和數(shù)組數(shù)據(jù)類型
數(shù)組是屬于同一類型的元素的集合。切片是數(shù)組頂部的方便、靈活且功能強(qiáng)大的包裝器。本文就來和大家聊聊Go中切片和數(shù)組的使用,需要的可以參考一下2023-03-03
Golang庫(kù)插件注冊(cè)加載機(jī)制的問題
這篇文章主要介紹了Golang庫(kù)插件注冊(cè)加載機(jī)制,這里說的插件并不是指的golang原生的可以在buildmode中加載指定so文件的那種加載機(jī)制,需要的朋友可以參考下2022-03-03

