program-doc-pb3使用

安装

1
2
3
4
5
# 下载pb
https://github.com/protocolbuffers/protobuf/releases

# 配置环境变量
将解压出来的protoc.exe放在一全英文路径下,并把其路径名放在windows环境变量下的path下。

使用

pb命令

命令 描述
-h 帮助手册
-IPATH,--proto_path=PATH 指定proto目录,可以指定多个
1
protoc -I=源地址 --xxx_out=目标地址 xxx/xxx.proto

语法

  • pack1/test1.proto
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
syntax = "proto3"; 					// (1)

package com.pack1; // (2)

enum StudentType // (3)
{
GOOD = 0;
BAD = 1;
}

message StudentInfo { // (4)
string name = 1; // (5)
repeated int32 socre = 2; // (6)
StudentType sType = 3;
}

message StudentInfoReq {
int32 sId = 1;
int32 opt = 2;
}

message StudentInfoRes {
int32 code = 1;
int32 sId = 2;
StudentInfo sInfo = 3;
}
  • pack1/test2.proto
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
syntax = "proto3"; 

package com.pack1;
import "pack1/test1.proto"; // (7)

message TeacherInfo {
string name = 1;
}

message TeacherInfoReq {
int32 tId = 1;
}

message TeacherInfoRes {
int32 code = 1;
int32 sId = 2;
TeacherInfo tInfo = 3;
repeated StudentInfo sInfo = 4; // (8)
}
  • pack2/test3.proto
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
syntax = "proto3"; 

package com.pack2;

import "pack1/test1.proto"; // (9)
import "pack1/test2.proto";

message SchoolInfoReq {
int32 sId = 1;
}

message SchoolInfoRes {
int32 code = 1;
int32 sId = 2;
repeated com.pack1.StudentInfo sInfo = 3; // (10)
repeated com.pack1.TeacherInfo tInfo = 4;
}
  • (1):指明我们使用的是proto3语法,若不指定该行 protocol buffer 编译器会认为是 proto2 。该行必须是文件的第一个非空或非注释行。

  • (2):指定包名

  • (3):定义枚举

  • (4):定义结构体

  • (5):定义普通变量

  • (6):定义数组

  • (7):引入同目录的包

  • (8):定义同目录包的结构体

  • (9):引入不同目录的包

  • (10):定义不同目录的包的结构体

  • 编译命令

1
2
3
protoc -I=D:\test_protoc --java_out=D:\test_protoc pack1/test1.proto
protoc -I=D:\test_protoc --java_out=D:\test_protoc pack1/test2.proto
protoc -I=D:\test_protoc --java_out=D:\test_protoc pack2/test3.proto

字段编号

息中定义的每个字段都有一个唯一编号。字段编号用于在消息二进制格式中标识字段,同时要求消息一旦使用字段编号就不应该改变。注意一点 1 到 15 的字段编号需要用 1 个字节来编码,编码同时包括字段编号和字段类型。16 到 2047 的字段变化使用 2 个字节。因此应将 1 到 15 的编号用在消息的常用字段上。注意应该为将来可能添加的常用字段预留字段编号。

关键字

关键字 描述
singular 默认值,非数组
repeated 数组
reserved 在采取彻底删除或注释掉某个字段的方式来更新消息类型时,将来其他用户再更新该消息类型时可能会重用这个字段编号。后面再加载该 .ptoto 的旧版本时会引发好多问题,例如数据损坏,隐私漏洞等。一个防止该问题发生的办法是将删除字段的编号(或字段名称,字段名称会导致在 JSON 序列化时产生问题)设置为保留项 reserved。protocol buffer 编译器在用户使用这些保留字段时会发出警告。(注意,不能在同一条 reserved 语句中同时使用字段编号和名称。)

在 proto3 中,标量数值类型的重复字段默认会使用 packed 压缩编码。

注释

使用 C/C++ 风格的 ///* ... */ 语法在 .proto 文件添加注释。

语言支持

当 protocol buffer 编译器作用于一个 .proto 文件时,编辑器会生成基于所选编程语言的关于 .proto 文件中描述消息类型的相关代码 ,包括对字段值的获取和设置,序列化消息用于输出流,和从输入流解析消息。

  • 对于 C++, 编辑器会针对于每个 .proto 文件生成.h 和 .cc 文件,对于每个消息类型会生成一个类。
  • 对于 Java, 编译器会生成一个 .java 文件和每个消息类型对应的类,同时包含一个特定的 Builder类用于构建消息实例。
  • Python 有些不同 – Python 编译器会对于 .proto 文件中每个消息类型生成一个带有静态描述符的模块,以便于在运行时使用 metaclass 来创建必要的 Python 数据访问类。
  • 对于 Go, 编译器会生成带有每种消息类型的特定数据类型的定义在.pb.go 文件中。
  • 对于 Ruby,编译器会生成带有消息类型的 Ruby 模块的 .rb 文件。
  • 对于Objective-C,编辑器会针对于每个 .proto 文件生成pbobjc.h 和 pbobjc.m. 文件,对于每个消息类型会生成一个类。
  • 对于 C#,编辑器会针对于每个 .proto 文件生成.cs 文件,对于每个消息类型会生成一个类。
  • 对于 Dart,编辑器会针对于每个 .proto 文件生成.pb.dart 文件,对于每个消息类型会生成一个类。

数据类型

.proto Type Notes C++ Type Java Type Python Type[2] Go Type Ruby Type C# Type PHP Type Dart Type
double double double float float64 Float double float double
float float float float float32 Float float float double
int32 使用变长编码。负数的编码效率较低——若字段可能为负值,应使用 sint32 代替。 int32 int int int32 Fixnum or Bignum (as required) int integer int
int64 使用变长编码。负数的编码效率较低——若字段可能为负值,应使用 sint64 代替。 int64 long int/long[3] int64 Bignum long integer/string[5] Int64
uint32 使用变长编码。 uint32 int[1] int/long[3] uint32 Fixnum or Bignum (as required) uint integer int
uint64 使用变长编码。 uint64 long[1] int/long[3] uint64 Bignum ulong integer/string[5] Int64
sint32 使用变长编码。符号整型。负值的编码效率高于常规的 int32 类型。 int32 int int int32 Fixnum or Bignum (as required) int integer int
sint64 使用变长编码。符号整型。负值的编码效率高于常规的 int64 类型。 int64 long int/long[3] int64 Bignum long integer/string[5] Int64
fixed32 定长 4 字节。若值常大于2^28 则会比 uint32 更高效。 uint32 int[1] int/long[3] uint32 Fixnum or Bignum (as required) uint integer int
fixed64 定长 8 字节。若值常大于2^56 则会比 uint64 更高效。 uint64 long[1] int/long[3] uint64 Bignum ulong integer/string[5] Int64
sfixed32 定长 4 字节。 int32 int int int32 Fixnum or Bignum (as required) int integer int
sfixed64 定长 8 字节。 int64 long int/long[3] int64 Bignum long integer/string[5] Int64
bool bool boolean bool bool TrueClass/FalseClass bool boolean bool
string 包含 UTF-8 和 ASCII 编码的字符串,长度不能超过 2^32 。 string String str/unicode[4] string String (UTF-8) string string String
bytes 可包含任意的字节序列但长度不能超过 2^32 。 string ByteString str []byte String (ASCII-8BIT) ByteString string List
enum 枚举,必须有一个 0 值,才可以作为数值类型的默认值。0 值常量必须作为第一个元素

默认值

当解析消息时,若消息编码中没有包含某个元素,则相应的会使用该字段的默认值。默认值依据类型而不同:

  • 字符串类型,空字符串
  • 字节类型,空字节
  • 布尔类型,false
  • 数值类型,0
  • 枚举类型,第一个枚举元素
  • 内嵌消息类型,依赖于所使用的编程语言。

对于可重复类型字段的默认值是空的( 通常是相应语言的一个空列表 )。

注意一下标量字段,在消息被解析后是不能区分字段是使用默认值(例如一个布尔型字段是否被设置为 false )赋值还是被设置为某个值的。例如你不能通过对布尔值等于 false 的判断来执行一个不希望在默认情况下执行的行为。同时还要注意若一个标量字段设置为默认的值,那么是不会被序列化以用于传输的。

链接

下载链接