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 ...
随机推荐
- K2与OData和Swagger的集成
最近K2陆续发布了一些好消息,从与Box的集成到今年取得的融资.这儿还有一个:K2近期宣布获得了DData和Swagger REST的支持,保障K2 Appit和Blackpearl的用户能建立基于工 ...
- NET Memory Profiler 跟踪.net 应用内存
NET Memory Profiler 跟踪.net 应用内存 用 .NET Memory Profiler 跟踪.net 应用内存使用情况--基本应用篇 作者:肖波 .net 框架号称永远 ...
- android Camera 录像时旋转角度
录像保存时,旋转角度要与所拍录像时的角度保持一致,否则,看起来就会出现角度不度,巅倒等问题. 一般在开始录像之前会先去初始化录像 initializeRecorder 中会去读取当前的录像或拍照的旋转 ...
- Java开源GIS系统
uDig 基于Eclipse RCP的uDig开源项目既是一个GeoSpatial应用程序也是一个平台开发者可通过这个平台来创建新的在uDig基础上衍生的应用程序,uDig是Web地理信息系统的一 ...
- matlab figure 窗口最大化
http://blog.163.com/yinhexiwen@126/blog/static/6404826620122942057214/ % figure 窗口最大化,坐标轴也随着窗口变大而相应变 ...
- 再次遇到\r\n转\r问题
帮助小伙伴做jenkins的环境搭建.以为5分钟的事情,但是发现了一个诡异的问题.总是提示SVN的url不合法“URL '%s' is not properly URI-encoded”. 由于选择了 ...
- Orchard 刨析:Logging
最近事情比较多,有预研的,有目前正在研发的,都是很需要时间的工作,所以导致这周只写了两篇Orchard系列的文章,这边不能保证后期会很频繁的更新该系列,但我会写完这整个系列,包括后面会把正在研发的东西 ...
- cryptdb中wrapper.lua的分析
因为cryptDB是在mysql-proxy的基础上来实现了,可以看成是为mysql-proxy添加了新的.为mysql-proxy已经为开发人员提供了相应的接口.如果开发人员只需要通过lua脚本语言 ...
- javascript基础(1)
1.前言 ECMAscript解释,用来解释JS代码 DOM 文档对象模型,浏览器在做显示时需要渲染DOM树 BOM 浏览器对象模型,可以控制浏览器的行为,代码的兼容性很差 2.基本类型 数字类型: ...
- javascript中数组Array的方法
一.常用方法(push,pop,unshift,shift,join)push pop栈方法,后进先出var a =[1,2,3];console.log(a.push(40)); //4 返回数组的 ...