1. 简介
Protocol Buffers是一种序列化数据结构的方法。对于通过导线或存储数据进行通信的程序开发上是很有用的。这个方法包含一个接口描述语言,描述一些数据结构,并且提供程序工具根据这些描述产生代码,用于将这些数据结构产生或解析数据流。
首先,protobuf是一个**开源 项 目(官方站点在“这里 ”),而且是后台很硬的开源项目。网上现有的大部分(至少80%)开源项目,要么是某人单干、要么是几个闲杂人等合伙搞。而protobuf则不然,它是 鼎鼎大名的Google公司开发出来,并且在Google内部久经考验的一个东东。由此可见,它的作者绝非一般闲杂人等可比。 那这个听起来牛X的东东到底有啥用处捏?简单地说,这个东东干的事儿其实和XML **差不多,也就是把某种数据结构的信息,以某种格式保存起来。主要用于数据存储、传输协议格式等场合。有同学可能心理犯嘀咕了:放着好好的XML不用,干嘛重新发明轮子啊?!先别急,后面俺自然会有说道。 话说到了去年(大约是08年7月),Google突然大发慈悲,把这个好东西贡献给了开源社区。这下,像俺这种喜欢捡现成的家伙可就有福啦!貌似喜欢 捡现成的家伙还蛮多滴,再加上 Google的号召力,开源后不到一年,protobuf的人气就已经很旺了。所以俺为了与时俱进,就单独开个帖子来忽悠一把。引用来自这里
ProBuffer 分为两个版本
- pro2
- pro3
2. 安装
请戳这里
3. 数据类型
类型 | C++类型 | Java类型 |
---|---|---|
double | double | double |
float | float | float |
int32 | int32 | int |
int64 | int64 | long |
....
4. 使用
4.1 先瞅瞅是什么样子的
message Person {
required string name = 1; //的姓名
required int32 id = 2; //唯一id
optional string email = 3;//电子邮箱
}
message
:表示一个消息定义。
required
:表示这个参数是必选的,如果没有值会全部为空。
optional
:表示这个参数是可选,没有好像没什么影响,值为null。
repeated
:这个会生成数组。
//
:表示注释
每个参数后面都会跟上一个tag,从1开始,每个tag从115暂用1个字节,162047占用2个字节。
所以我们使用的时候应该让经常出现的字段使用1~15这些tag,最小的tag数值是1,最大的数值是 2^29 - 1
通过命令可以生成对应的model
- objc_out 表示的是输出Object-C文件
- java_out 输出java文件
....
protoc --plugin=/usr/local/bin/protoc-gen-objc a.proto --objc_out=./
这是一个最基本的消息体,可以通过命令生成对应语言的model
IOS 需要安装类库,让生成的model序列化成二进制
使用cocoapod
pod 'Protobuf', '~> 3.1.0'
```
######4.2 定义一个带数组参数的消息体
```
message People{
repeated string name = 1;
}
```
从消息体来看这个name 这个参数是`数组`,其中的内容类型是`string`,要注意的是 `repeated`是不能用 `required`和`optional`修饰的。
如果数组里面装的事基本类型就要添加`[packed=true]`
```
message People{
repeated int32 repeated_number = 4 [packed=true];
}
```
######4.3 保留区域(Reserved Fields)
保留字段,编程过程中某些功能没有想好,可以先把该tag 进行保留,以备以后使用。
```
message Foo {
reserved 2, 15, 9 to 11;
reserved "foo", "bar";
}
```
######4.4 设置默认值
```
optional int32 result_per_page = 3 [default = 10];
```
###### ~~4.5 枚举类型(Enumerations)~~
```
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];
}
```
用关键字**` enum `**定义一个枚举
######4.6 使用别的message类型
```
message SearchResponse {
repeated Result result = 1;
}
message Result {
required string url = 1;
optional string title = 2;
repeated string snippets = 3;
}
```
######4.7 导入
当需要使用导入其他的消息的时候可以使用下面的方法导入
```
import "myproject/other_protos.proto";
```
当然也可以导入`proto3`文件,但是`proto2`的枚举类型不能用在`proto3`的语法里面。
######4.8 message 的嵌套
有别于 4.6
```
message SearchResponse {
message Result {
required string url = 1;
optional string title = 2;
repeated string snippets = 3;
}
repeated Result result = 1;
}
```
如果想使用这用嵌套类型在去定义别的message可以这样使用`Parent.Type`
例如:
```
message SomeOtherMessage {
optional SearchResponse.Result result = 1;
}
```
可以各种深度嵌套
```
message Outer { // Level 0
message MiddleAA { // Level 1
message Inner { // Level 2
required int64 ival = 1;
optional bool booly = 2;
}
}
message MiddleBB { // Level 1
message Inner { // Level 2
required int32 ival = 1;
optional bool booly = 2;
}
}
}
```
***
#####下面来说说比较实用的功能#####
***
######~~4.8 拓展(Extensions)~~
Extensions可以让程序不经过大的改动就可以增加新的功能。
```
message Foo {
// ...
extensions 100 to 199;
}
```
以上声明了一个叫做Foo的message 在改消息的Extensions部分声明了它的tag从100到199 这些Extensions 的tag可以在以后的扩展中实用,让我们看看Extensions 的使用
```
extend Foo {
optional int32 bar = 126;
}
```
以上说明Foo 现在有了一个optional int32类型的bar。
但是如果要使用Extensions部分的内容就有点不一样了。(***这是C++的风格***)
```
Foo foo;
foo.SetExtension(bar, 15);
```
在生成的class 中有一下方法来操作Extensions
```
HasExtension(),
ClearExtension(),
GetExtension(),
MutableExtension(),
AddExtension(),
```
######4.8 使用one of
先看看定义
```
message SampleMessage {
oneof test_oneof {
string name = 4;
SubMessage sub_message = 9;
}}
```
可以在one of 上加任何类型,但是不能加`required `,`optional`,`repeated` 这些关键字
让我们看看one of 的使用
```
SampleMessage message;
message.set_name("name");
CHECK(message.has_name());
message.mutable_sub_message(); // Will clear name field.CHECK(!message.has_name());
```
上面的`SampleMessage` 定义了一个message,如果向`name`赋值,那么name 现在的值就是`‘name’`,但是如果再向`sub_message `赋值,那么name 这个域将会为空,现在我们应该明白了**`one of`**的作用了吧.
#5. Map
首先看看map 的声明
```
map<key_type, value_type> map_field = N;
```
以下几点应当特别注意
- Extensions 不支持map
- map 不能设置为`repeated`,`optional`,`required `
如果map不支持`repeated` 怎么办,咱们有解决方法!
```
message MapFieldEntry {
key_type key = 1;
value_type value = 2;
}
repeated MapFieldEntry map_field = N;
```
未完待续。。。