Golang使用gob实现结构体的序列化过程详解

 更新时间:2023年03月08日 08:30:04   作者:梦想画家  
Golang struct类型数据序列化用于网络传输数据或在磁盘上写入数据。在分布式系统中,一端生成数据、然后序列化、压缩和发送;在另一端,接收数据、然后解压缩、反序列化和处理数据,整个过程必须快速有效

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, "\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
}

列表数据序列化

首先创建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, "\t", 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,"\t",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, '\n')
       // 写入文件
	_, err = file.Write(bs)
	if err != nil {
		return
	}
	return
}

到此这篇关于Golang使用gob实现结构体的序列化过程详解的文章就介绍到这了,更多相关Golang结构体序列化内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Go runtime 调度器之系统调用引起的抢占

    Go runtime 调度器之系统调用引起的抢占

    本文解析了在Go语言中,当goroutine执行的系统调用时间过长时,系统如何通过监控和抢占机制来处理,以维持运行效率和资源分配的平衡,通过具体的示例和流程图,详细展示了系统调用过程中的抢占操作,感兴趣的朋友跟随小编一起看看吧
    2024-09-09
  • Golang 模块引入及表格读写业务快速实现示例

    Golang 模块引入及表格读写业务快速实现示例

    这篇文章主要为大家介绍了Golang模块引入及表格读写业务的快速实现示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-07-07
  • 深入解析Go语言中crypto/subtle加密库

    深入解析Go语言中crypto/subtle加密库

    本文主要介绍了深入解析Go语言中crypto/subtle加密库,详细介绍crypto/subtle加密库主要函数的用途、工作原理及实际应用,具有一定的参考价值,感兴趣的可以了解一下
    2024-02-02
  • Golang如何读取单行超长的文本详解

    Golang如何读取单行超长的文本详解

    这篇文章主要给大家介绍了关于Golang如何读取单行超长文本的相关资料,文中通过实例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2021-12-12
  • golang 40行代码实现通用协程池

    golang 40行代码实现通用协程池

    golang协程机制很方便的解决了并发编程的问题,但是协程并不是没有开销的,所以也需要适当限制一下数量。这篇文章主要介绍了golang 40行代码实现通用协程池,需要的朋友可以参考下
    2018-08-08
  • Go语言中init函数和defer延迟调用关键词详解

    Go语言中init函数和defer延迟调用关键词详解

    这篇文章主要介绍了Go语言中init函数和defer延迟调用关键词,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-03-03
  • 一文教你如何快速学会Go的切片和数组数据类型

    一文教你如何快速学会Go的切片和数组数据类型

    数组是属于同一类型的元素的集合。切片是数组顶部的方便、灵活且功能强大的包装器。本文就来和大家聊聊Go中切片和数组的使用,需要的可以参考一下
    2023-03-03
  • Golang中正则表达式语法及相关示例

    Golang中正则表达式语法及相关示例

    正则表达式是一种用于匹配和操作文本的强大工具,它使用特殊的字符和语法来定义模式,下面这篇文章主要给大家介绍了关于Golang中正则表达式语法及相关示例的相关资料,需要的朋友可以参考下
    2024-05-05
  • Golang库插件注册加载机制的问题

    Golang库插件注册加载机制的问题

    这篇文章主要介绍了Golang库插件注册加载机制,这里说的插件并不是指的golang原生的可以在buildmode中加载指定so文件的那种加载机制,需要的朋友可以参考下
    2022-03-03
  • Golang内存管理之内存逃逸分析

    Golang内存管理之内存逃逸分析

    逃逸分析是指由编译器决定内存分配的位置,不需要程序员指定,这篇文章主要为大家详细介绍了Golang中内存逃逸分析的几种方法,需要的可以参考一下
    2023-07-07

最新评论