xml | json | protoBuf | |
---|---|---|---|
体积 | 大 | 小 | 很小 |
传输效率 | 相对json慢 | 快 | 很快 |
简单性 | 结构复杂 | 结构简单 | 相对简单 |
通用性 | 没有json普遍 | 普遍 | 不普遍 |
可读性 | 凑合 | 好 | 差,二进制文件 |
下载链接:https://github.com/protocolbuffers/protobuf/releases
在任意地方新建一个protobuf
文件夹,将下载好的压缩包解压到protobuf
文件夹中,本文在E盘
下新建protobuf
文件夹。解压后,进入其bin
目录,会看见protoc.exe
文件
配置环境变量
方法一:直接将protoc.exe
复制到GOPATH/bin
中
方法二:配置环境变量:
环境变量
-系统变量
-Path
-编辑
-新建
-proto.exe所在的路径,本文即:E:\protobuf\bin
为了统一方便管理,建议使用方法一。
验证:打开cmd
,输入protoc --version
下载:go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
最后在GOPATH/bin
中看到protoc-gen-go.exe
文件说明安装成功。
protoc xxx.proto --go_out=.
或者
protoc --go_out=. xxx.proto
或者
protoc --go_out=. *.proto
参考文档(需):https://developers.google.com/protocol-buffers/docs/proto3
syntax = "proto3"; //指定版本信息,不指定会报错
package pb; //后期生成go文件的包名
//message为关键字,作用为定义一种消息类型
message Person{
// 名字
string name = 1;
// 年龄
int32 age = 2 ;
}
enum test{
int32 age = 0;
}
- protobuf消息的定义(或者称为描述)通常都写在一个以 .proto 结尾的文件中。
- 该文件的第一行指定正在使用
proto3
语法:如果不这样做,协议缓冲区编译器将假定正在使用proto2。这也必须是文件的第一个非空的非注释行。- 第二行package指明当前是pb包(生成go文件之后和Go的包名保持一致)
- 最后message关键字定义一个Person消息体,类似于go语言中的结构体,是包含一系列类型数据的集合。许多标准的简单数据类型都可以作为字段类型,包括
bool
,int32
,float
,double
,和string
。也可以使用其他message类型作为字段类型。- 在message中有一个字符串类型的value成员,该成员编码时用1代替名字。我们知道,在json中是通过成员的名字来绑定对应的数据,但是Protobuf编码却是通过成员的
唯一编号
来绑定对应的数据,因此Protobuf编码后数据的体积会比较小,能够快速传输,缺点是不利于阅读。
消息由至少一个字段组合而成,类似于Go语言中的结构体,每个字段都有一定的格式:
.proto类型 | Go类型 | 介绍 |
---|---|---|
double | float64 | 64位浮点数 |
float | float32 | 32位浮点数 |
int32 | int32 | 使用可变长度编码。编码负数效率低下——如果你的字段可能有负值,请改用sint32。 |
int64 | int64 | 使用可变长度编码。编码负数效率低下——如果你的字段可能有负值,请改用sint64。 |
uint32 | uint32 | 使用可变长度编码。 |
uint64 | uint64 | 使用可变长度编码。 |
sint32 | int32 | 使用可变长度编码。符号整型值。这些比常规int32s编码负数更有效。 |
sint64 | int64 | 使用可变长度编码。符号整型值。这些比常规int64s编码负数更有效。 |
fixed32 | uint32 | 总是四字节。如果值通常大于228,则比uint 32更有效 |
fixed64 | uint64 | 总是八字节。如果值通常大于256,则比uint64更有效 |
sfixed32 | int32 | 总是四字节。 |
sfixed64 | int64 | 总是八字节。 |
bool | bool | 布尔类型 |
string | string | 字符串必须始终包含UTF - 8编码或7位ASCII文本 |
bytes | []byte | 可以包含任意字节序列 |
protobuf除了上面的简单类型还有一些复杂的用法,如下:
message嵌套
messsage除了能放简单数据类型外,还能存放另外的message类型,如下:
syntax = "proto3"; //指定版本信息,不指定会报错,默认proto2
package pb; //后期生成go文件的包名
//message为关键字,作用为定义一种消息类型
message Person{
// 名字
string name = 1; //编号可以不从1开始,但是不能重复。也不能使用19000 ~ 19999
// 年龄
int32 age = 2 ;
//定义一个message
message PhoneNumber {
string number = 1;
int64 type = 2;
}
PhoneNumber phone = 3;
}
repeated关键字
repeadted关键字类似与go中的切片
,编译之后对应的也是go的切片,用法如下:
syntax = "proto3"; //指定版本信息,不指定会报错
package pb; //后期生成go文件的包名
//message为关键字,作用为定义一种消息类型
message Person{
// 名字
string name = 1;
// 年龄
int32 age = 2 ;
//定义一个message
message PhoneNumber {
string number = 1;
int64 type = 2;
}
repeated PhoneNumber phone = 3;
}
默认值
解析数据时,如果编码的消息不包含特定的单数元素,则解析对象对象中的相应字段将设置为该字段的默认值。不同类型的默认值不同,具体如下:
enum关键字
在定义消息类型时,可能会希望其中一个字段有一个预定义的值列表。比如说,电话号码字段有个类型,这个类型可以是,home,work,mobile。我们可以通过enum在消息定义中添加每个可能值的常量来非常简单的执行此操作。实例如下:
syntax = "proto3"; //指定版本信息,不指定会报错
package pb; //后期生成go文件的包名
//message为关键字,作用为定义一种消息类型
message Person{
// 名字
string name = 1;
// 年龄
int32 age = 2 ;
//定义一个message
message PhoneNumber {
string number = 1;
PhoneType type = 2;
}
repeated PhoneNumber phone = 3;
}
//enum为关键字,作用为定义一种枚举类型
enum PhoneType {
MOBILE = 0; //枚举值必须从0开始
HOME = 1;
WORK = 2;
}
如上,enum的第一个常量映射为0,每个枚举定义必须包含一个映射到零的常量作为其第一个元素。这是因为:
- 必须有一个零值,以便我们可以使用0作为数字默认值。
- 零值必须是第一个元素,以便与proto2语义兼容,其中第一个枚举值始终是默认值。
enum还可以为不同的枚举常量指定相同的值来定义别名。如果想要使用这个功能必须讲allow_alias
选项设置为true,负责编译器将报错。示例如下:
syntax = "proto3"; //指定版本信息,不指定会报错
package pb; //后期生成go文件的包名
//message为关键字,作用为定义一种消息类型
message Person{
// 名字
string name = 1;
// 年龄
int32 age = 2 ;
//定义一个message
message PhoneNumber {
string number = 1;
PhoneType type = 2;
}
repeated PhoneNumber phone = 3;
}
//enum为关键字,作用为定义一种枚举类型
enum PhoneType {
//如果不设置将报错
option allow_alias = true;
MOBILE = 0;
HOME = 1;
WORK = 2;
Personal = 2;
}
oneof关键字
如果有一个包含许多字段的消息,并且最多只能同时设置其中的一个字段(联合体),则可以使用oneof功能,示例如下:
message Person{
// 名字
string name = 1;
// 年龄
int32 age = 2 ;
//定义一个message
message PhoneNumber {
string number = 1;
PhoneType type = 2;
}
repeated PhoneNumber phone = 3;
oneof data{
string school = 5; //编号不能重复,根据习惯顺次往下编
int32 score = 6;
}
}