Golang Protocol Buffers数据格式教程

本文我们介绍如何在Golang应用中使用Protocol Buffers数据格式。包括Protocol Buffers的定义,与传统xml、json相比的优势,并通过几个示例进行实践。

Protocol Buffers数据格式

Protocol Buffers是Google推出的一种数据格式。我们知道json/xml可用在不同语言中存储数据,实现序列化和反序列化。它与json/xml格式相比,存储大小要小很多。
Golang Protocol Buffers数据格式教程

假设有person对象,我们用三种数据格式进行对比描述:

<person>
  <name>Elliot</name>
  <age>24</age>
</person>

用json描述会小点:

{
  "name": "Elliot",
  "age": 24
}

如果同样数据用protocol buffer表示:

[10 6 69 108 108 105 111 116 16 24]

仔细观察会发现,从数组第二个位置开始Elliot被表示出来, E=69, l=108,依此下去,最后是年龄24.

编码格式比我们看到的要复杂得多,我也在尝试对它了解更多,如果需要建议查看谷歌文档。现在虽然我们的示例表示的大小与json差不多。下面我们考虑更复杂的场景,大小差异会更多。

简单对象序列化示例

首先我们需要安装protoc工具,下载地址:https://github.com/protocolbuffers/protobuf/releases ;

windows64对应文件为:protoc-3.19.4-win64.zip;下载后解压protoc.exe至go安装路径下bin目标,确保可以在任何位置执行该文件。

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

安装完成后,在命令行中测试protoc命令是否可用。

下面我们定义 protobuf 数据格式,我们对上面person对象进行修改。首先指定使用的语法,这里使用proto3格式。然后指定文件位置:option go_package ="../pb"; 表示person.proto文件位于pb目录下,接着指定包,完整内容如下:

syntax="proto3";
option go_package ="../pb";

package pb;

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

最后在pb目录下执行命令生成对应go文件:

protoc --go_out=. person.proto

正常生成不会出现错误,在pb目录中生成person.pb.go文件。下面我们定义Person对象并使用protobuf格式进行编码,然后使用fmt.Println(data)输出 protobuf格式对象:

package main

import (
	"fmt"
	"github.com/dataz.cn/wordcount/pb"
	"github.com/golang/protobuf/proto"
	"log"

)

func main() {
	elliot := &pb.Person{
		Name: "Elliot",
		Age:  24,
	}

	data, err := proto.Marshal(elliot)
	if err != nil {
		log.Fatal("marshaling error: ", err)
	}

	fmt.Println(data)

	newElliot := &pb.Person{}
	err = proto.Unmarshal(data, newElliot)
	if err != nil {
		log.Fatal("unmarshaling error: ", err)
	}

	fmt.Println(newElliot.GetAge())
	fmt.Println(newElliot.GetName())
}

接着对编码后的对象进行反序列化生成新的对象,打印其属性进行验证。

运行上面代码,输出如下:

[10 6 69 108 108 105 111 116 16 24]
24
Elliot

嵌套类型序列化示例

上面示例稍显简单,实际应用会更复杂。下面我们看嵌套类型序列化情况,Employee对象中嵌套SocialFollowers对象:

syntax="proto3";
option go_package ="../pb";

package pb;

message SocialFollowers {
  int32 weixin = 1;
  int32 weibo  = 2;
}

message Employee {
  string name = 1;
  int32 age = 2;
  SocialFollowers socialFollowers = 3;
}

与上面示例的命令生成对应go文件。下面示例展示嵌套对象的序列化与反序列化过程:

package main

import (
	"fmt"
	"github.com/dataz.cn/wordcount/pb"
	"github.com/golang/protobuf/proto"
	"log"
)

func main() {

	elliot := pb.Employee{
		Name: "Elliot",
		Age:  24,
		SocialFollowers: &pb.SocialFollowers{
			Weixin: 2500,
			Weibo: 1400,
		},
	}

	data, err := proto.Marshal(&elliot)
	if err != nil {
		log.Fatal("序列化错误: ", err)
	}

	newElliot := &pb.Employee{}
	err = proto.Unmarshal(data, newElliot)
	if err != nil {
		log.Fatal("反序列错误: ", err)
	}

	fmt.Println(newElliot.GetName())
	fmt.Println(newElliot.GetAge())
	fmt.Println(newElliot.SocialFollowers.GetWeixin())
	fmt.Println(newElliot.SocialFollowers.GetWeibo())
}

再次运行输出结果为:

Elliot
24
2500
1400

总结

本文我们介绍了Google的protocol buffer数据格式,并通过示例展示利用该格式序列化、反序列化对象的过程。

上一篇:1:React-ts-antd项目antd自定义样式


下一篇:mmap