Go 实践|序列化和反序列化

背景

在软件开发过程中序列化和反序列化是一个重要的步骤,它能够让数据在存储和传输变得更简单,高效。在 Go 中有很多现成的包让序列化和反序列化的工作的变的很简单。本文主要对 JSON, XML, Gob, Protocol Buffers (protobuf), MessagePack, and YAML.等流行格式的学习和记录。

序列化和反序列化

序列化是将集合类型的数据结构转换为可以方便保存到文件或通过网络传输的格式的过程。反序列化是相反的过程,就是将序列化的数据反过来序列化成初始的数据集合。常见的序列化格式包括 JSON、XML 和二进制格式,例如 Gob、Protocol Buffers、MessagePack 和 YAML。

每种格式都有其使用的场景和优势:

  • JSON:适用于服务间的数据交换;作为可读且易编辑的配置文件和数据文件;用于 API 响应和请求体。结构直观简洁,相较于XML更轻量。
  • XML:适用于一些严格要求文档结构的场景,如SVG、RSS;C# 中作为配置文件的格式,SOAP协议中使用。可扩展自定义标签,支持严格的模式定义和验证
  • Gob:Go 语言标准库一部分,用于go应用之间的高效数据序列化和反序列化,或者RPC 通信,传输数据性能更高,占用空间小,使用方便。
  • Protocol Buffers:适用于对性能和数据一致性要求高的系统,如微服务之间数据传输,尤其适用于大型系统。高性能且有明确的消息结构
  • MessagePack :适用于带宽和性能要求高的移动应用或游戏网络通信
  • YAML :广泛应用于配置文件

使用何种格式主要依赖于你的场景和要求,比如可读性,性能或兼容性的要求。

序列化和反序列化的实践

JSON

Json是一种轻量级数据交换格式,简单易懂编写放便,也方便机器解析和生成。在 Go 中,encoding/json 包提供了使用 JSON 的方法。json.Marshal 用于序列化数据 json.Unmarshal 方法用于反序列数据

go 复制代码
type Person struct {
    Name  string `json:"name"`
    Age   int    `json:"age"`
    Email string `json:"email,omitempty" `
}

// 序列化
data, err := json.Marshal(p)
if err != nil {
    fmt.Println("序列化失败:", err)
    return
}

// 反序列化
var p2 Person
err = json.Unmarshal(data, &p2)
    if err != nil {
    fmt.Println("反序列化失败:", err)
    return
}

例子中使用 struct 的标签对Json 字段名称的自定义, 标签中 omitempty 的标识作用是省略序列化输出的空字段。始终对序列化和反序列化过程进行错误处理,避免数据损坏或崩溃。

XML

XML(可扩展标记语言)是另一种用于序列化的格式,特别是在需要严格数据模式的应用程序中。在 Go 中,encoding/xml 包提供了使用 JSON 的方法。xml.MarshalIndent 用于序列化,并带有缩进以提高可读性, xml.Unmarshal 用于反序列化。

go 复制代码
type Person struct {
    XMLName xml.Name `xml:"person"`
    Name    string   `xml:"name"`
    Age     int      `xml:"age"`
    Email   string   `xml:"email"`
}

// 序列化
data, err := xml.MarshalIndent(p, "", "  ")
if err != nil {
    fmt.Println("序列化失败:", err)
    return
}

var p2 Person
err = xml.Unmarshal(data, &p2)
if err != nil {
    fmt.Println("反序列化失败:", err)
    return
}

例子中 struct 的标签也支持XML字段的定义,和json 不同是结构体中多了使用 XMLName 管理 xml 的 namespace。对于错误的处理也是始终都要进行处理的。

Gob

Gob 格式是golang 专用的二进制序列化的序列化格式,简洁且高效。使用 encoding/gob 包可以完成对应序列化和反序列化的工作。

go 复制代码
type Person struct {
    Name  string
    Age   int
    Email string
}
// 序列化
var buffer bytes.Buffer
encoder := gob.NewEncoder(&buffer)

err := encoder.Encode(p)
if err != nil {
    fmt.Println("Error serializing:", err)
    return
}

fmt.Println("Serialized Gob:", buffer.Bytes())

// 反序列化
var p2 Person
decoder := gob.NewDecoder(&buffer)
err = decoder.Decode(&p2)
if err != nil {
    fmt.Println("Error deserializing:", err)
    return
}

使用 Gob 序列化需要先使用NewEncoder 初始化一个序列化器在调用对应序列化方法 Encode和 Decode。Gob 相较于 JSON 和XML 更加轻量,处理更快速。在序列化和反序列过程保证类型安全。所以在处理一些复杂或接口类型时需要使用 gob.Register 进行注册,避免编码错误。

ProtocolBuffers(Protobuf)

protobuf 是谷歌开发的一种与语言和平台无关的机制,相较于 JSON 和XML 更加轻量且处理更快速。使用 protobuf 需要先定义一个数据类型文件 .proto 文件。然后再对该文件进行编译生成 Go 代码。进行序列化和反序列工作只需要引用 github.com/golang/protobuf/proto包。

ini 复制代码
// .proto 文件
syntax = "proto3";

message Person {
  string name = 1;
  int32 age = 2;
  string email = 3;
}

// go 文件
// 序列化
data, err := proto.Marshal(p)
if err != nil {
    log.Fatal("序列化失败: ", err)
}
// 反序列化
var p2 personpb.Person
err = proto.Unmarshal(data, &p2)
if err != nil {
    log.Fatal("反序列化失败: ", err)
}

使用 protoc-gen-go 等库可以轻松将protobuf集成在go项目中,且兼容性可以支持向后和向前兼容。因为可以在 message 中添加字段而不用去动现有的代码。

MessagePack

messagePack 也是一种高效的二进制序列化格式,特别适用在关注带宽的场景中。使用 github.com/vmihailenco/msgpack/v5包即可完成序列化相关工作。

go 复制代码
// 序列化
data, err := msgpack.Marshal(p)
if err != nil {
    log.Fatal("序列化失败: ", err)
}


// 反序列
var p2 Person
err = msgpack.Unmarshal(data, &p2)
if err != nil {
    log.Fatal("反序列化失败: ", err)
}

Yaml

通常应用于配置文件中,是一种方便阅读的序列化格式。使用 gopkg.in/yaml.v2包即可完成序列化相关工作。

go 复制代码
// 序列化
data, err := yaml.Marshal(p)
if err != nil {
    log.Fatal("序列化失败: ", err)
}

// 反序列
var p2 Person
err = yaml.Unmarshal(data, &p2)
if err != nil {
    log.Fatal("反序列化失败: ", err)
}

其作为配置文件时读写方便,但需要注意缩进的问题。YAML 还支持复杂数据结构,包括嵌套映射和列表。

yaml 复制代码
//yaml 配置文件

server:
  name: tool-web
  port: 8080
redis:
  dns: "..."
  maxConn: 10
相关推荐
it噩梦22 分钟前
springboot 工程使用proguard混淆
java·spring boot·后端
从种子到参天大树1 小时前
SpringBoot源码阅读系列(二):自动配置原理深度解析
后端
从种子到参天大树1 小时前
SpringBoot源码阅读系列(一):启动流程概述
后端
m0_748254881 小时前
Spring Boot实现多数据源连接和切换
spring boot·后端·oracle
庄周de蝴蝶2 小时前
一次 MySQL IF 函数的误用导致的生产小事故
后端·mysql
韩数2 小时前
Nping: 支持图表实时展示的多地址并发终端命令行 Ping
后端·rust·github
18号房客2 小时前
云原生后端开发(一)
后端·云原生
胡尔摩斯.3 小时前
SpringMVC
java·开发语言·后端·spring·代理模式
Bony-4 小时前
Go语言高并发实战案例分析
开发语言·后端·golang
ac-er88884 小时前
Golang并发机制以及它所使⽤的CSP并发模型
开发语言·后端·golang