Go语言常见数据格式(JSON、XML、MsgPack、Protobuf)使用总结

不晚
不晚
发布时间:2026-10-15 | 5人浏览过
原创

在分布式系统中,节点间的数据传输必须依赖统一的数据交换格式。Go语言提供了多种内置和第三方包来支持JSON、XML等文本格式,以及MsgPack、Protobuf等二进制格式。本文通过代码示例,详解这四种格式在Go中的序列化、反序列化操作及结构体标签配置,并重点展示Protobuf在多语言协作中的标准开发流程。

结果与目标

掌握Go语言中主流数据格式的编码技巧,能够根据不同业务场景(如可读性、存储体积、跨语言兼容性)选择合适的序列化方式,并能独立搭建Protobuf开发环境。

准备条件

  • 已安装Go语言运行环境。
  • 熟悉Go结构体(struct)与指针的基本用法。
  • 对于Protobuf部分,需提前下载 protoc 编译器及 protoc-gen-go 插件。

真实操作顺序

第1步:使用JSON格式进行数据交换

目的:利用内置的 encoding/json 包,实现结构体到JSON字符串及文件的高效转换。

关键参数与动作: 使用 json.Marshal 进行序列化,json.Unmarshal 进行反序列化。注意路径分隔符在不同操作系统下的差异。

package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"math/rand"
)

type Student struct {
	Name string
	Age  int
	Sex  string
}

//写入json数据
func writeJson(filename string) (err error) {
	var students []*Student
	//随机生成10个学生数据
	for i := 0; i < 10; i++ {
		p := &Student{
			Name: fmt.Sprintf("name%d", i),
			Age:  rand.Intn(100),
			Sex:  "Man",
		}
		students = append(students, p)
	}

	//执行序列化操作
	data, err := json.Marshal(students)
	if err != nil {
		fmt.Printf("=marshal failed, err:%v\n", err)
		return
	}

	//将数据写到一个文件当中
	err = ioutil.WriteFile(filename, data, 0755)
	if err != nil {
		fmt.Printf("write file failed, err:%v\n", err)
		return
	}

	return
}

//读取json数据
func readJson(filename string) (err error) {
	var students []*Student
	data, err := ioutil.ReadFile(filename)
	if err != nil {
		return
	}

	err = json.Unmarshal(data, &students)
	if err != nil {
		return
	}

	for _, v := range students {
		fmt.Printf("%#v\n", v)
	}
	return
}

第2步:使用XML格式构建结构化文档

目的:利用 encoding/xml 包处理具有层级关系的XML数据,适用于需要保留树状结构的配置或日志场景。

入口与重要参数: 通过结构体标签(Tag)控制XML节点名称、属性(attr)、字符数据(chardata)及空值省略(omitempty)。

  • - XMLName:指定最外层节点名,若省略则使用结构体名。
  • - ,attr:将字段转为XML元素属性。
  • - ,omitempty:空值时省略该字段。
  • - MarshalIndent:用于生成格式化缩进的XML。
//最外层的xml
type Servers struct {
	XMLName xml.Name  `xml:"Servers"`
	Version string    `xml:"version,attr"`
	Servers []*Server `xml:"server"`
}

//具体的server
type Server struct {
	ServerName string `xml:"serverName"`
	ServerIP   string `xml:"serverIP"`
}

写文件方法与JSON类似,核心区别在于序列化调用 xml.MarshalIndent:

func writeXml(fileName string) (err error) {
	var serverList []*Server
	for i := 0; i < 2; i++ {
		s := &Server{
			ServerName: fmt.Sprintf("Server%d", i),
			ServerIP:   fmt.Sprintf("192.168.1.%d", i),
		}
		serverList = append(serverList, s)
	}

	var myServers *Servers = &Servers{
		Version: "2.0",
		Servers: serverList,
	}

	//执行序列化操作,第二个参数为前缀,第三个为缩进字符串
	data, err := xml.MarshalIndent(myServers, "", "    ")
	if err != nil {
		fmt.Printf("=marshal failed, err:%v\n", err)
		return
	}

	err = ioutil.WriteFile(fileName, data, 0755)
	if err != nil {
		fmt.Printf("write file failed, err:%v\n", err)
		return
	}

	return
}

读取时使用 xml.Unmarshal(data, &xxx) 即可还原结构。

第3步:使用MsgPack优化二进制传输

目的:解决JSON/XML文本格式占用空间较大的问题,利用MsgPack以更紧凑的二进制形式存储数据。

操作说明: MsgPack无官方内置包,需引入第三方库 github.com/vmihailenco/msgpack。其API设计与JSON高度一致,通常只需将 json.Marshal 替换为 msgpack.Marshal。

在实际应用中,生成大量数据时,MsgPack的文件体积显著小于JSON文本。例如生成10000条学生数据时,二进制编码效率优势明显:

第4步:使用Protobuf实现多语言协作

目的:利用Google推出的Protocol Buffers解决不同编程语言(Go/Java/C#等)之间的数据兼容性问题,并通过变长编码提升性能。

开发流程:编写IDL描述文件 → 生成目标语言代码 → 序列化/反序列化。

A.安装protoc编译器

从 GitHub官方仓库 下载对应系统的 protoc 二进制文件,解压后将其所在目录添加至系统环境变量PATH中,或在Go项目的 GOPATH/bin 目录下使用。

验证安装是否成功:

B.安装Go语言插件

执行以下命令获取代码生成工具:

go get -u github.com/golang/protobuf/protoc-gen-go

C.创建.proto定义文件

定义消息结构,注意枚举类型第一个值必须为0,且需指定proto版本。

syntax = "proto3";
package school;

enum Sex {
    male = 0;
    female = 1;
    other = 2;
}

message Student {
    Sex sex = 1;
    string Name = 2;
    int32 Age = 3;
}

message Class {
    repeated Student Students = 1;
    string Name = 2;
}

D.生成Go代码

使用protoc命令,指定输出路径和源文件:

protoc --go_out=. ./school.proto

执行后将在当前目录生成对应的Go文件,可直接在项目中使用:

E.序列化和反序列化

序列化:使用 proto.Marshal(&obj)。

func writeProto(filename string) (err error) {
	var students []*school.Student
	for i := 0; i < 30; i++ {
		var sex = (school.Sex)(i % 3)
		student := &school.Student{
			Name: fmt.Sprintf("Student_%d", i),
			Age:  15,
			Sex:  sex,
		}
		students = append(students, student)
	}

	var myClass school.Class
	myClass.Name = "我的班级"
	myClass.Students = students

	data, err := proto.Marshal(&myClass)
	if err != nil {
		fmt.Printf("marshal proto buf failed, err:%v\n", err)
		return
	}

	err = ioutil.WriteFile(filename, data, 0755)
	if err != nil {
		fmt.Printf("write file failed, err:%v\n", err)
		return
	}
	return
}

反序列化:使用 proto.Unmarshal(data, &obj)。

func readProto(filename string) (err error) {
	var mySchool school.Class
	data, err := ioutil.ReadFile(filename)
	if err != nil {
		return
	}
	err = proto.Unmarshal(data, &mySchool)
	if err != nil {
		return
	}

	fmt.Printf("proto:%v\n", mySchool)
	return
}

完成判断与排错

验证完成:程序无报错运行,且在指定路径下生成了包含正确数据的txt/json/xml/proto文件,控制台打印出解析后的结构体内容。

常见错误排查: 在使用Protobuf时,若遇到 undefined: proto.ProtoPackageIsVersion3 错误,通常是因为 protoc 编译器版本与 golang/protobuf 库版本不一致。

  1. 清理缓存:rm -rf $GOPATH/pkg/mod/github.com/golang/protobuf 或直接删除相关文件夹后重新下载。
  2. 重新编译插件:在 $GOPATH/src/github.com/golang/protobuf/protoc-gen-go 目录下执行 go install。
  3. 检查包管理工具:如果使用Godep或Go Modules,确保锁定的protobuf版本与运行时一致。

简要总结

JSON和XML适合对可读性要求较高的场景;MsgPack适合追求更高压缩比的二进制存储;而Protobuf凭借其在大小和速度上的双重优势,成为微服务和高并发系统中跨语言通信的首选。以上就是Go语言中JSON、XML、MsgPack和Protobuf的详细使用方法,更多关于Go网络编程和数据处理的资料请关注本站其它相关文章!

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表