Protocol Buffers(Protobuf) 官方文档--Protobuf语言指南
Protocol Buffers(Protobuf) 官方文档--Protobuf语言指南
约定:为方便书写,ProtocolBuffers在下文中将已Protobuf代替。
本指南将向您描述如何使用protobuf定义i结构化Protobuf数据,包括.proto文件语法和如何使用.proto文件生成数据存取类。
作为一个参考指南,本文档将以示例的形式一步步向您介绍Protobuf的特点。您可以参考您所选择的语言的示例。tutorial
--------------------------------------小小的分割线-----------------------------------------
定义一个消息类型
首先,看一个非常简单的例子,比如说你想定义一个 搜索请求消息 ,每个搜索请求都有一个 查询的字符串(关键字:比如我们上百度搜索 《报告老板》),和我们搜索出来的一个感兴趣的网页,以及搜索到的所有网页总数。 来看看这个.proto文件是如何定义的。
1 message SearchRequest {
2 required string query = 1;
3 optional int32 page_number = 2;
4 optional int32 result_per_page = 3;
5 }
这个"搜索请求"消息指定了三个字段(名称/属性 组合),每一个你想要包含在这类型的信息内的东西,都必须有一个字段,每个字段有一个名称和类型!
指定字段类型
在上面的示例中,所有的字段都是标量类型(scalar types):两个整数(integers:page_number
和 result_per_page)和一个字符串(string:query:查询的关键字),不过你可以在你的字段内指定符合类型。包括枚举类型(enumerations)
和其他的消息类型
分配指定标签号
如你所见,每个消息的字段都有一个唯一的数字标签,这些标签用来表示你的字段在二进制消息(message binary format)中处的位置。并且一旦指定标签号,在使用过程中是不可以更改的,标记这些标签号在1-15的范围内每个字段需要使用1个字节用来编码这一个字节包括字段所在的位置和字段的类型!(需要更多关于编码的信息请点击Protocol Buffer Encoding)。标签号在16-2047需要使用2个字节来编码。所以你最好将1-15的标签号为频繁使用到的字段所保留。如果将来可能会添加一些频繁使用到的元素,记得留下一些1-15标签号。
最小可指定的标签号为1,最大的标签号为229 - 1或者536870911。不能使用19000-19999的标签号(FieldDescriptor::kFirstReservedNumber 至 FieldDescriptor::kLastReservedNumber) 这些标签号是为protobuf内部实现所保留的,如果你在.proto文件内使用了这些标签号Protobuf编译器将会报错!
指定字段规则
消息字段可以被指定为以下三种:
required
: 完整的消息内必须拥有此字段。此字段是必须拥有的 (双方都要有)optional
: 完整的消息内此字段是可选的,可拥有也可以没有(双方可选)repeated
: 完整的消息内本字段的值可以拥有任意个,重复的值的次数会保存下来。(双方可选,数组)
因为历史的原因:repeated字段如果是基本的数字类型的话会无法编码。新的代码应该使用特殊的关键字[packed=true] 来使其得到有效的编码.例如
- repeated int32 samples = 4 [packed=true];
- repeated int32 samples = 4 [packed=true];
注意:你应该小心将字段设置为required,如果你希望在某些情况下取消required字段的读写,它将改变字段为optional属性,旧的的读取方将会认为此消息不完全。可能会无意的将其丢弃。你应该考虑自定义一个消息检查程序。google的一些工程师认为使用optinal字段的好处大于required。但是显然这个观点并不是通用的。
添加更多的消息类型
多个消息类型可以定义在同一个.proto文件内,这对定义多个有关联的消息是是十分有用的。例如,如果你想定义一个用于回复SearchResponse消息,你可以像这样在.proto内添加。
- message SearchRequest {
- required string query = 1;
- optional int32 page_number = 2;
- optional int32 result_per_page = 3;
- }
- message SearchResponse {
- ...
- }
- message SearchRequest {
- required string query = 1;
- optional int32 page_number = 2;
- optional int32 result_per_page = 3;
- }
- message SearchResponse {
- ...
- }
添加注释
添加注释的方式和C/C++是一样的。使用//
- message SearchRequest {
- required string query = 1;
- optional int32 page_number = 2;// Which page number do we want?
- optional int32 result_per_page = 3;// Number of results to return per page.
- }
- message SearchRequest {
- required string query = 1;
- optional int32 page_number = 2;// Which page number do we want?
- optional int32 result_per_page = 3;// Number of results to return per page.
- }
.proto文件会生成什么?
当你使用protobuf编译器编译一个.proto文件,它会生成在.proto内你描述的消息类型的操作代码,这些代码是根据你所选择的编程功能语言决定的。这些操作代码内包含了设置字段值 和读取字段值,以及序列化到输出流 和 从输入流反序列化。
C++:编译器会按照每个.proto文件生成与其对应的.h和.cc文件,每个消息类似都有独立的消息操作类。
Java:编译器将会生成一个.java文件和一个操作类,此操作类为所有消息类型所共有, 使用一个特别的Builder类为每个消息类型实例化
.
Python:有一点不同 – 编译器会为每个消息生成一个模块每个模块有一个静态描述符, 该模块与一个元类在运行时创建一个需要的数据操作类。
从你所选择语言的例程,你可以找到更多关于API的内容, 需要关于API的详细信息, 参考: API reference.
标量值类型
一个消息的字段如果要使用标量可使之为以下类型 –这个表格显示了在.proto文件内可以指定的类型, 与自动生成的相对类型!
.proto Type | Notes | C++ Type | Java Type | Python Type[2] |
---|---|---|---|---|
double | double | double | float | |
float | float | float | float | |
int32 | Uses variable-length encoding. Inefficient for encoding negative numbers – if your field is likely to have negative values, use sint32 instead. | int32 | int | int |
int64 | Uses variable-length encoding. Inefficient for encoding negative numbers – if your field is likely to have negative values, use sint64 instead. | int64 | long | int/long[3] |
uint32 | Uses variable-length encoding. | uint32 | int[1] | int/long[3] |
uint64 | Uses variable-length encoding. | uint64 | long[1] | int/long[3] |
sint32 | Uses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int32s. | int32 | int | int |
sint64 | Uses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int64s. | int64 | long | int/long[3] |
fixed32 | Always four bytes. More efficient than uint32 if values are often greater than 228. | uint32 | int[1] | int |
fixed64 | Always eight bytes. More efficient than uint64 if values are often greater than 256. | uint64 | long[1] | int/long[3] |
sfixed32 | Always four bytes. | int32 | int | int |
sfixed64 | Always eight bytes. | int64 | long | int/long[3] |
bool | bool | boolean | boolean | |
string | A string must always contain UTF-8 encoded or 7-bit ASCII text. | string | String | str/unicode[4] |
bytes | May contain any arbitrary sequence of bytes. | string | ByteString | str |
你可以在Protocol Buffer Encoding.找到更多关于.这些类型如何编码,如何序列化定义消息的信息!
[1] 在Java中, 无符号32位和64位整数与其有符号相对应, 最高位用来保存符号!
[2] 在所有情况下, 设置某个字段的值将会执行类型检查确保其值是合法的!
[3] 64位或32位无符号整数在解码中会以long来解码, 给字段赋值的时候可以是int.但是在所有情况下,赋值的时候会转变为其目标类型 . 详见 [2].
[4] Python的字符串在解码时候会以unicode来描述,但是同样的可以给其赋值为ascii字符串 (此乃弦外之音).
Optional 字段与其默认值
如上所述,在描述一个消息的时候可以用optional指定字段约束,一个消息可以包含也可以不包含optional元素。当一个消息被解析,如果其没有一个optional字段,被解析的消息对象就会将其相对的字段设置为其字段的默认值。这个默认值可以在描述消息的时候被指定。例如。比如你想设置SearchRequest的
result_per_page的默认值为10.
- optional int32 result_per_page = 3 [default = 10];
- optional int32 result_per_page = 3 [default = 10];
如果一个optional字段没有被指定其默认值。其默认值被自动替换为:
1.字符串:为空字符串.
2.bool:为false.
3.数字类型:为0;
4.枚举值:为第一个枚举值
枚举值
当你定义消息格式的时候, 也许你希望其中的一个字段的的值为一个预定义的值类表中的一个. 比方说, 在SearchRequest消息中
你想定义一个 corpus
字段, corpus字段的值可以为:" UNIVERSAL
, WEB
, IMAGES
, LOCAL
, NEWS
, PRODUCTS
或者 VIDEO"
. 你可以非常简单的给你的消息添加一个枚举类型 - 一个枚举字段类型其值指定被指定为一个常量的集合 (如果你尝试赋值一个不一样的值, 解析器将会认为这个字段为未知字段). 在下面的例子中 我们给corpus字段指定为枚举类型与其可能的值 :
- message SearchRequest {
- required string query = 1;
- optional int32 page_number = 2;
- optional int32 result_per_page = 3 [default = 10];
- enum Corpus {
- UNIVERSAL = 0;
- WEB = 1;
- IMAGES = 2;
- LOCAL = 3;
- NEWS = 4;
- PRODUCTS = 5;
- VIDEO = 6;
- }
- optional Corpus corpus = 4 [default = UNIVERSAL];
- }
- message SearchRequest {
- required string query = 1;
- optional int32 page_number = 2;
- optional int32 result_per_page = 3 [default = 10];
- enum Corpus {
- UNIVERSAL = 0;
- WEB = 1;
- IMAGES = 2;
- LOCAL = 3;
- NEWS = 4;
- PRODUCTS = 5;
- VIDEO = 6;
- }
- optional Corpus corpus = 4 [default = UNIVERSAL];
- }
你可以为一个枚举常量定义别名,如果你需要这样做的话需要将allow_alias设置为true。否则如果出现别名的话编译器将会报错!
- enum EnumAllowingAlias {
- option allow_alias = true;
- UNKNOWN = 0;
- STARTED = 1;
- RUNNING = 1;
- }
- enum EnumNotAllowingAlias {
- UNKNOWN = 0;
- STARTED = 1;
- // RUNNING = 1; //不注释这行的话会引发一个错误异常
- enum EnumAllowingAlias {
- option allow_alias = true;
- UNKNOWN = 0;
- STARTED = 1;
- RUNNING = 1;
- }
- enum EnumNotAllowingAlias {
- UNKNOWN = 0;
- STARTED = 1;
- // RUNNING = 1; //不注释这行的话会引发一个错误异常
枚举值的范围必须在32位整数之内.枚举值的编码使用可变长度的整数,负数会非常低效所以,不推荐使用。你可以在一个消息内部定义一个枚举类型,比如上面的例子。或者也可以在消息的外部定义。这些枚举类型是可以在.proto文件内中重用的,你可以在消息内定义个枚举类型。然后在不同的消息类型中使用它!可以使用 MessageType.EnumType来访问。
当你运行编译器编译.proto文件中的枚举类型时,生成的代码会有一个相对应的枚举值(JAVA 或者C++),或者有一个特别的EnumDescriptor类(python)用于在运行时生成一个符号常量集合。
更多关于枚举类型的信息查询 generated code guide 选择你使用的语言。
待续....................
Protocol Buffers(Protobuf) 官方文档--Protobuf语言指南的更多相关文章
- Protocol Buffers官方文档(proto3语言指南)
本文是对官方文档的翻译,大部分内容都是引用其他一些作者的优质翻译使文章内容更加通俗易懂(自己是直译,读起来有点绕口难理解,本人英文水平有限),参考的文章链接在文章末尾 这篇指南描述如何使用protoc ...
- 《KAFKA官方文档》入门指南(转)
1.入门指南 1.1简介 Apache的Kafka™是一个分布式流平台(a distributed streaming platform).这到底意味着什么? 我们认为,一个流处理平台应该具有三个关键 ...
- 官方文档 恢复备份指南一 Introduction to Backup and Recovery
1.备份分为:物理备份和逻辑备份 物理备份:备份数据文件 控制文件 归档日志文件 逻辑备份:EXP EXPDP备份等 物理备份为主,逻辑做补充 2.错误的类型 ...
- 官方文档 恢复备份指南六 Configuring the RMAN Environment: Advanced Topics
RMAN高级设置. 本章内容: Configuring Advanced Channel Options 高级通道选项 Configuring Advanced Backup Options 高级备 ...
- 官方文档 恢复备份指南三 Recovery Manager Architecture
本节讨论以下问题: About the RMAN Environment 关于RMAN环境 RMAN Command-Line Client ...
- 官方文档 恢复备份指南八 RMAN Backup Concepts
本章内容 Consistent and Inconsistent RMAN Backups Online Backups and Backup Mode Backup Sets Image Copie ...
- 官方文档 恢复备份指南四 Starting and Interacting with the RMAN Client
本章讲: Starting and Exiting RMAN Specifying the Location of RMAN Output ...
- 官方文档 恢复备份指南二 Getting Started with RMAN
本章对RMAN进行基本的熟悉和了解 1.Overview of the RMAN Environment RMAN运行时需要的最小环境: target database ...
- 官方文档 恢复备份指南七 Using Flashback Database and Restore Points
本章内容: Understanding Flashback Database, Restore Points and Guaranteed Restore Points Logging for Fla ...
随机推荐
- Python快速教程 尾声(转)
原文地址: http://www.cnblogs.com/vamei/p/3603046.html 作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留 ...
- Brief introduce to Iometer
<本人原创,纯粹为了练习英文博客的写作.转载请注明出处谢谢!非技术博客 http://shiyanch.lofter.com/ > *:first-child { margin-top: ...
- CSS 实现加载动画之四-圆点旋转
圆点旋转也是加载动画中经常用到的.其实现方式和菊花旋转一样,只不过一个是线条形式,一个是圆点形式.圆点按照固定的旋转角度排列,加上延时的改变透明度的动画就可以实现.这个实现也比较简单. 1. 动画截图 ...
- poj2154-color-polyan次二面体+欧拉函数优化
N<=1e9,O(nlogn)的做法会超时.从枚举置换转变为枚举轮换长度,然后可以利用欧拉函数,把复杂度变为O(√n * logn) /*---------------------------- ...
- StretchDIBits函数
该函数将DIB中矩形区域内像素使用的颜色数据拷贝到指定的目标矩形中.如果目标矩形比源矩形大小要大,那么函数对颜色数据的行和列进行拉伸,以与目标矩形匹配.如果目标矩形大小要比源矩形小,那么该函数通过使用 ...
- android加固签名工具(源码下载)
背景 每次android加固了都要命令行签名好麻烦,正好之前做了个图标生成工具. 所以改了改,比写批处理还要省事. 原理 其实就是用winform程序调用控制台执行命令,android签名的命令如下 ...
- Swift与Objective-c 混编CocoaPods 引入第三方库遇到的问题 (一)
最近Swift 这么火也想尝试着用一下.考虑到Swift 出来的时间也不长.还有就是就是苹果更新的过于平凡 暂时还是不要将现有项目都用swift开发. 先来看看我遇到的问题: 问题一.
- Provider 错误 '80004005' 未指定的错误 /conn.asp,行 23
网站本来正常,由于网站修改了title标签的内容,想要百度快照快点更新. 就自己提交快照.在下面网站: http://zhanzhang.baidu.com/sitesubmit/index 提交UR ...
- 字符串string类型转换成DateTime或DateTime?类型
常用的Convert.ToDateTime方法 //将含有正确日期格式的string类型转换成DateTime类型 string strDate = "2014-08-01"; D ...
- 小记:Quartz 当 Job 执行时间超过触发间隔时间时所发生的情况
一个普通的 Job 实现如下: public class Job1 : IJob { public void Execute(IJobExecutionContext context) { Conso ...