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] 来使其得到有效的编码.例如

  1. repeated int32 samples = 4 [packed=true];
  1. repeated int32 samples = 4 [packed=true];

注意:你应该小心将字段设置为required,如果你希望在某些情况下取消required字段的读写,它将改变字段为optional属性,旧的的读取方将会认为此消息不完全。可能会无意的将其丢弃。你应该考虑自定义一个消息检查程序。google的一些工程师认为使用optinal字段的好处大于required。但是显然这个观点并不是通用的。

添加更多的消息类型

多个消息类型可以定义在同一个.proto文件内,这对定义多个有关联的消息是是十分有用的。例如,如果你想定义一个用于回复SearchResponse消息,你可以像这样在.proto内添加。

  1. message SearchRequest {
  2. required string query = 1;
  3. optional int32 page_number = 2;
  4. optional int32 result_per_page = 3;
  5. }
  6. message SearchResponse {
  7. ...
  8. }
  1. message SearchRequest {
  2. required string query = 1;
  3. optional int32 page_number = 2;
  4. optional int32 result_per_page = 3;
  5. }
  6. message SearchResponse {
  7. ...
  8. }

添加注释

添加注释的方式和C/C++是一样的。使用//

  1. message SearchRequest {
  2. required string query = 1;
  3. optional int32 page_number = 2;// Which page number do we want?
  4. optional int32 result_per_page = 3;// Number of results to return per page.
  5. }
  1. message SearchRequest {
  2. required string query = 1;
  3. optional int32 page_number = 2;// Which page number do we want?
  4. optional int32 result_per_page = 3;// Number of results to return per page.
  5. }

.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.

  1. optional int32 result_per_page = 3 [default = 10];
  1. optional int32 result_per_page = 3 [default = 10];

如果一个optional字段没有被指定其默认值。其默认值被自动替换为:

1.字符串:为空字符串.

2.bool:为false.

3.数字类型:为0;

4.枚举值:为第一个枚举值

枚举值

当你定义消息格式的时候, 也许你希望其中的一个字段的的值为一个预定义的值类表中的一个. 比方说, 在SearchRequest消息中你想定义一个 corpus 字段, corpus字段的值可以为:" UNIVERSALWEBIMAGESLOCALNEWSPRODUCTS 或者 VIDEO". 你可以非常简单的给你的消息添加一个枚举类型 - 一个枚举字段类型其值指定被指定为一个常量的集合 (如果你尝试赋值一个不一样的值, 解析器将会认为这个字段为未知字段). 在下面的例子中 我们给corpus字段指定为枚举类型与其可能的值 :

  1. message SearchRequest {
  2. required string query = 1;
  3. optional int32 page_number = 2;
  4. optional int32 result_per_page = 3 [default = 10];
  5. enum Corpus {
  6. UNIVERSAL = 0;
  7. WEB = 1;
  8. IMAGES = 2;
  9. LOCAL = 3;
  10. NEWS = 4;
  11. PRODUCTS = 5;
  12. VIDEO = 6;
  13. }
  14. optional Corpus corpus = 4 [default = UNIVERSAL];
  15. }
  1. message SearchRequest {
  2. required string query = 1;
  3. optional int32 page_number = 2;
  4. optional int32 result_per_page = 3 [default = 10];
  5. enum Corpus {
  6. UNIVERSAL = 0;
  7. WEB = 1;
  8. IMAGES = 2;
  9. LOCAL = 3;
  10. NEWS = 4;
  11. PRODUCTS = 5;
  12. VIDEO = 6;
  13. }
  14. optional Corpus corpus = 4 [default = UNIVERSAL];
  15. }

你可以为一个枚举常量定义别名,如果你需要这样做的话需要将allow_alias设置为true。否则如果出现别名的话编译器将会报错! 

  1. enum EnumAllowingAlias {
  2. option allow_alias = true;
  3. UNKNOWN = 0;
  4. STARTED = 1;
  5. RUNNING = 1;
  6. }
  7. enum EnumNotAllowingAlias {
  8. UNKNOWN = 0;
  9. STARTED = 1;
  10. // RUNNING = 1;  //不注释这行的话会引发一个错误异常
  1. enum EnumAllowingAlias {
  2. option allow_alias = true;
  3. UNKNOWN = 0;
  4. STARTED = 1;
  5. RUNNING = 1;
  6. }
  7. enum EnumNotAllowingAlias {
  8. UNKNOWN = 0;
  9. STARTED = 1;
  10. // RUNNING = 1;  //不注释这行的话会引发一个错误异常

枚举值的范围必须在32位整数之内.枚举值的编码使用可变长度的整数,负数会非常低效所以,不推荐使用。你可以在一个消息内部定义一个枚举类型,比如上面的例子。或者也可以在消息的外部定义。这些枚举类型是可以在.proto文件内中重用的,你可以在消息内定义个枚举类型。然后在不同的消息类型中使用它!可以使用 MessageType.EnumType来访问。当你运行编译器编译.proto文件中的枚举类型时,生成的代码会有一个相对应的枚举值(JAVA 或者C++),或者有一个特别的EnumDescriptor类(python)用于在运行时生成一个符号常量集合。

更多关于枚举类型的信息查询 generated code guide 选择你使用的语言。

待续....................

Protocol Buffers(Protobuf) 官方文档--Protobuf语言指南的更多相关文章

  1. Protocol Buffers官方文档(proto3语言指南)

    本文是对官方文档的翻译,大部分内容都是引用其他一些作者的优质翻译使文章内容更加通俗易懂(自己是直译,读起来有点绕口难理解,本人英文水平有限),参考的文章链接在文章末尾 这篇指南描述如何使用protoc ...

  2. 《KAFKA官方文档》入门指南(转)

    1.入门指南 1.1简介 Apache的Kafka™是一个分布式流平台(a distributed streaming platform).这到底意味着什么? 我们认为,一个流处理平台应该具有三个关键 ...

  3. 官方文档 恢复备份指南一 Introduction to Backup and Recovery

    1.备份分为:物理备份和逻辑备份    物理备份:备份数据文件  控制文件  归档日志文件     逻辑备份:EXP EXPDP备份等 物理备份为主,逻辑做补充     2.错误的类型         ...

  4. 官方文档 恢复备份指南六 Configuring the RMAN Environment: Advanced Topics

    RMAN高级设置. 本章内容: Configuring Advanced Channel Options  高级通道选项 Configuring Advanced Backup Options 高级备 ...

  5. 官方文档 恢复备份指南三 Recovery Manager Architecture

    本节讨论以下问题: About the RMAN Environment                        关于RMAN环境 RMAN Command-Line Client        ...

  6. 官方文档 恢复备份指南八 RMAN Backup Concepts

    本章内容 Consistent and Inconsistent RMAN Backups Online Backups and Backup Mode Backup Sets Image Copie ...

  7. 官方文档 恢复备份指南四 Starting and Interacting with the RMAN Client

    本章讲: Starting and Exiting RMAN Specifying the Location of RMAN Output                                ...

  8. 官方文档 恢复备份指南二 Getting Started with RMAN

    本章对RMAN进行基本的熟悉和了解   1.Overview of the RMAN Environment    RMAN运行时需要的最小环境:      target database       ...

  9. 官方文档 恢复备份指南七 Using Flashback Database and Restore Points

    本章内容: Understanding Flashback Database, Restore Points and Guaranteed Restore Points Logging for Fla ...

随机推荐

  1. C语言 百炼成钢17

    //题目49:老师将糖果分成若干份,让学生按任意次序领取,第一个领取的,得到1份加上剩余糖果的1/10, //第二个领取的,得到2份加上剩余糖果的1/10,第三个领取的,得到3份加上剩余糖果的1/10 ...

  2. 加密算法使用(五):RSA使用全过程

    RSA是一种非对称加密算法,适应RSA前先生成一对公钥和私钥. 使用公钥加密的数据可以用私钥解密,同样私钥加密的数据也可以用公钥解密, 不同之处在于,私钥加密数据的同事还可以生成一组签名,签名是用来验 ...

  3. Windows和Linux上用C与Lua交互

    Windos2010编译lua的方法: http://blog.csdn.net/appletreesujie/article/details/12065369 Linux编译lua的方法: make ...

  4. 淘宝账号基于OAuth2.0的登录验证授权登陆第三方网站

    首先得有一个注册的appkey和App Secret   该流程分三个步骤: 第一步:通过用户授权获取授权码Code: 第二步:用上一步获取的Code和应用密钥(AppSecret)通过Https P ...

  5. 每日一SQL-善用DATEADD和DATEDIFF

    转自:http://www.dotblogs.com.tw/lastsecret/archive/2010/10/04/18097.aspx 上個星期去Tech-Day聽了幾場有趣的課,其中一堂是楊志 ...

  6. JS案例之7——瀑布流布局(2)

    这个例子与上一篇类似,唯一的区别是排序的方式有差别.上一篇是在高度最小的列里插入内容,这个案例是按顺序放置内容. 两种方法各有优缺点.第一种需要在图片内容加载完成的情况下有效.这个例子不需要在wind ...

  7. Caffe学习系列(16):caffemodel可视化

    通过前面的学习,我们已经能够正常训练各种数据了.设置好solver.prototxt后,我们可以把训练好的模型保存起来,如lenet_iter_10000.caffemodel. 训练多少次就自动保存 ...

  8. Matlab中的数据类型

    Matlab中有15种基本数据类型,主要是整型.浮点.逻辑.字符.日期和时间.结构数组.单元格数组以及函数句柄等.         1.整型:(int8:uint8:int16:uint16:int3 ...

  9. HoloToolkit项目源码剖析 - Spatial Mapping功能实现

    就像我之前所描述的,HoloToolkit项目是微软基于Unity内置的底层API封装的一套工具集合,帮助我们快速使用Unity集成开发HoloLens应用. 本文主要通过源码研究其中Spatial ...

  10. .NET领域最为流行的IOC框架之一Autofac

    一.前言 Autofac是.NET领域最为流行的IOC框架之一,微软的Orchad开源程序使用的就是Autofac,Nopcommerce开源程序也是用的Autofac. Orchad和Nopcomm ...