Skip to main content
 首页 » 编程设计

Golang Protocol Buffers数据格式教程

2022年07月19日112artech

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

Protocol Buffers数据格式

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

假设有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数据格式,并通过示例展示利用该格式序列化、反序列化对象的过程。


本文参考链接:https://blog.csdn.net/neweastsun/article/details/123168569
阅读延展