protobuf是什么
protobuf,全称Google protocol buffer,Google公司内部的混合语言数据标准,用于RPC系统和持续数据存储系统
它是一种轻便高效的结构化数据存储格式,可以用于结构化数据串行化,或者说序列化,适合做数据存储或RPC数据交换格式,可用于通讯协议、数据存储等领域的语言无关、平台无关、可扩展的序列化结构数据格式。目前提供了 C++、Java、Python三种语言的
API
为什么要使用protobuf
提到protobuf,一般会与XML做比较,protobuf优点:
与XML相比,protobuf更小,更快,更简单,可以自定义数据结构,用代码生成器来生成可读代码;另外protobuf支持向后兼容,不必破坏老的数据格式的程序,即可进行升级,不必担心消息结构改变而造成的大规模代码重构或迁移问题;protobuf语义更清晰,无需类似XML解析器的东西,protobuf编译器会将.proto文件编译生成对应的数据访问类以对protobuf数据进行序列化、反序列化操作;protobuf无需学习复杂的文档对象模型,protobuf简单易学,拥有良好的文档和示例,能快速上手。
Protobuf缺点:
XML相比protobuf要成熟,已经成为行业标准,protobuf只是Google内部使用的工具,通用性比较差
Protobuf序列化后生成的是二进制消息,除非有.proto定义,没法直接读出protobuf的内容,而XML具有某种程度上的自解释性,可被人直接读取编辑;protobuf不适用基于文本的标记文档(HTML)建模
怎么使用protobuf
Protobuf简单例子
图1
组成部分:message关键字,类似java中的class关键字;HellowWorld消息名,类似java中的类名;required/optional/repeated是限定符,required表示序列化或反序列化之前,该字段不能为空,一个message中至少要有一个required限定字段;optional和repeated没有该限制,其中optional表示选填,可以设置默认值,一个message中允许0个或多个optional限定字段(参考图2),如果未设置,在序列化是如果该字段内容为空,则根据类型,如果类型为int32/int64则默认为0,如果类型为string则默认为空串,如果类型为boolean则默认为false;repeated多用来表示数组,repeated定义的字段允许0个或多个数据;int32/int64/string等类型为protobuf中的基本数据类型
图2
Protobuf支持消息嵌套,支持枚举,支持一个message作为另一个message的字段属性,如图3
图3
如何实现不同的.proto文件中,message公用呢?可以如java一般,引入import关键字,例如A.proto文件在pro路径下,且存在一个名为common的message,B.proto文件想引用common,则需要在文件的package(protobuf的包名,序列化后生成对应java文件的包名,c++文件的namespace)下,message之前引用:import
“pro/A.proto”
Protobuf的基本数据类型与java和c++对照表如图4
图4
Protobuf的options
Protocol Buffer允许我们在.proto文件中定义一些常用的选项,这样可以指示Protocol Buffer编译器帮助我们生成更为匹配的目标语言代码。Protocol
Buffer内置的选项被分为以下三个级别:
1. 文件级别,这样的选项将影响当前文件中定义的所有消息和枚举。
2. 消息级别,这样的选项仅影响某个消息及其包含的所有字段。
3. 字段级别,这样的选项仅仅响应与其相关的字段。
文件级别的选项有:
java_package—通过指定该选项可以让生成Java代码的包名为该选项值,例如[optionjava_package=”com.hik.web.proto”],则生成java文件的包是在com.hik.web.proto下,如果没有指定该选项,Java的包名则为package关键字指定的名称,此选项仅对生成java代码有效
java_outer_classname—该选项指定生成的Java类名,例如:[optionjava_outer_classname=”Hpp”],如果没有指定该选项,Java文件名为proto文件的名称,并且会将名称转换为驼峰模式,比如.proto文件名为my_proto.proto,则生成的java文件名为MyProto.java,此选项仅对java代码生效
optimize_for—Protocol Buffer定义三种优化级别SPEED/CODE_SIZE/LITE_RUNTIME。缺省情况下是SPEED。SPEED表示生成的代码运行效率高,但生成的代码编译后会占用更多的空间;CODE_SIZE与SPEED相反,生成的代码运行效率会低,但生成的代码编译后占用空间更小,适用于资源有限的平台,比如mobile;LITE_RUNTIME生成代码的执行效率高,并且生成编译后占用的空间也比较小,这是通过牺牲protobuf提供的反射功能实现的,使用该选项,Java或c++需要protobuf-lite相关包或连接
字段级别的选项有:
packed=true--对于数值型的repeated字段,如int32、int64等,在编码时并没有得到很好的优化,然而在新近版本的Protocol
Buffer中,可通过添加[packed=true]的字段选项,以通知Protocol Buffer在为该类型的消息对象编码时更加高效(该option在protobuf2.3.0以上版本才生效)
default=default_value—这个主要用于optional字段设置默认值,上面有介绍
protobuf命令行
图5
protoc--命令行编译工具
--proto_path等同于-I,指定要编译的proto文件目录,该选项可以指定多个
--java_out编译成Java文件,并指定生成java文件的目录,同样的还有cpp_out生成c++文件,python_out生成python文件
path/file.proto表示待编译的proto文件
可以编写一个protoc.bat文件内容如图6: