多平台下的数据存储新秀-PROTOBUF

Posted 精讲JAVA

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了多平台下的数据存储新秀-PROTOBUF相关的知识,希望对你有一定的参考价值。






protobuf是什么

protobuf是google旗下的一款平台无关,语言无关,可扩展的序列化结构数据格式。所以很适合用做数据存储和作为不同应用,不同语言之间相互通信的数据交换格式,只要实现相同的协议格式即同一proto文件被编译成不同的语言版本,加入到各自的工程中去。这样不同语言就可以解析其他语言通过protobuf序列化的数据。目前官网提供了C++,Python,JAVA,GO等语言的支持。

多平台下的数据存储新秀-PROTOBUF
protobuf定义

要想使用protobuf必须得先定义proto文件。所以得先熟悉protobuf的消息定义的相关语法。下面就来介绍

首先我们先定义一个proto文件,结构如下:

message Article {
required int32 article_id=1;
optional string article_excerpt=2;
repeated string article_picture=3;
}

message是消息定义的关键字上面我们主要定义了一个消息,这个消息包括文章ID,文章摘要,文章图片。下面给出消息定义的相关说明

required 表示这个字段必须的,必须在序列化的时候被赋值。

optional 代表这个字段是可选的,可以为0个或1个但不能大于1个。

repeated 则代表此字段可以被重复任意多次包括0次。

int32和string是字段的类型。后面是我们定义的字段名。

最后的1,2,3则是代表每个字段的一个唯一的编号标签,在同一个消息里不可以重复。这些编号标签用与在消息二进制格式中标识你的字段,并且消息一旦定义就不能更改。需要说明的是标签在1到15范围的采用一个字节进行编码。所以通常将标签1到15用于频繁发生的消息字段。编号标签大小的范围是1到2的29方 – 1。此外不能使用protobuf系统预留的编号标签(19000 -19999)。

当然protobuf支持更多的类型,比如bool,double,float,枚举,也可以是其他定义过的消息类型譬如前面的消息Article。支持的基本类型如下:

多平台下的数据存储新秀-PROTOBUF

我们定义一个数据比较多的article.proto文件来再次说明下proto语法的相关内容

syntax = "proto2";
message Article {
 required int32 article_id = 1;
 optional string article_excerpt = 2;
 repeated string article_picture = 3;
 optional int32  article_pagecount = 4 [default = 0];
 enum ArticleType {
   NOVEL = 0;
   PROSE = 1;
   PAPER = 2;
   POETRY = 3;
 }
 optional ArticleType article_type = 5 [default = NOVEL];
 message Author {
   required string name = 1; //作者的名字
   optional string phone = 2;
 }
 optional Author author = 6;
 repeated int32 article_numberofwords = 7 [packed=true];
 reserved  9, 10, 12 to 15;
 extensions 100 to 1000;
}
extend Article {
 optional int32 followers_count = 101;
 optional int32 likes_count= 102;
}
message Other {
 optional string other_info = 1;
 oneof test_oneof {
   string code1 = 2;
   string code2 = 3;
 }
}

此外reserved关键字主要用于保留相关编号标签,主要是防止在更新proto文件删除了某些字段,而未来的使用者定义新的字段时重新使用了该编号标签。这会引起一些问题在获取老版本的消息时,譬如数据冲突,隐藏的一些bug等。所以一定要用reserved标记这些编号标签以保证不会被使用上面proto文件,定义了enum枚举类型,嵌套的消息。甚至对原有的消息进行了扩展,也可以对字段设置默认值。添加注释等

当我们需要对消息进行扩展的时候,我们可以用extensions关键字来定义一些编号标签供第三方扩展。这样的好处是不需要修改原来的消息格式。就像上面proto文件,我们用extend关键字来扩展。只要扩展的字段编号标签在extensions定义的范围里。

对于基本数值类型,由于历史原因,不能被protobuf更有效的encode。所以在新的代码中使用packed=true可以更加有效率的encode。注意packed只能用于repeated 数值类型的字段。不能用于string类型的字段。

在消息Other中我们看到定义了一个oneof关键字。这个关键字作用比较有意思。当你设置了oneof里某个成员值时,它会自动清除掉oneof里的其他成员,也就是说同一时刻oneof里只有一个成员有效。这常用于你有许多optional字段时但同一时刻只能使用其中一个,就可以用oneof来加强这种效果。但需要注意的是oneof里的字段不能用required,optional,repeted关键字

当一个proto文件需要另一个proto文件的时候,我们可以通过import导入,就像下面这样:

import "article.proto";
message Book {
//定义消息体
}

protobuf也提供了包的定义,只要在文件开头定义package关键字即可。主要是为了防止命名冲突,不过对于Python语言在编译的时候会忽略包名。

package "foo.bar"
message  Book {
//定义消息体
}

1.不能改变已有的任何编号标签。修改更新定义的proto文件时,如果不遵守一定规则的话,修改的后proto文件可能会引发许多异常。在官网上对更新proto有以下几点要求

2.只能添加optional和repeated的字段。这样旧代码能够解析新的消息,只是那些新添加的字段会被忽略。但是序列化的时候还是会包含哪些新字段。而新代码无论是旧消息还是新消息都可以解析。

3.非required的字段可以被删除,但是编号标签不可以再次被使用,应该把它标记到reserved中去

4.非required可以被转换为扩展字段,只要字段类型和编号标签保持一致

5.相互兼容的类型,可以从一个类型修改为另一个类型,譬如int32的字段可以修改为int64

ptotobuf语法相对比较简单,一般都能很快熟悉上手。这里只是粗浅的介绍下,更多详细内容可以参考https://developers.google.com/protocol-buffers/docs/proto。


多平台下的数据存储新秀-PROTOBUF
protobuf实用干货


前期准备(下载安装protocol buffers)

由于google是被墙的,大家可以自行FQ,这里推荐一个网站可以直接通过添加hosts方式实现FQ(https://laod.cn/hosts/2016-google-hosts.html

  下载  protobuf-java-3.0.0.zip和protoc-3.0.0-win32.zip

  下载完成之后将两个压缩包分别解压。


参考资料


https://developers.google.com/protocol-buffers/docs/javatutorial

https://github.com/google/protobuf/

http://www.cnblogs.com/ungshow/archive/2011/12/27/2303257.html

http://blog.csdn.net/caisini_vc/article/details/5599468


关注【平凡文摘】更多资讯等你来


以上是关于多平台下的数据存储新秀-PROTOBUF的主要内容,如果未能解决你的问题,请参考以下文章

Protobuf 从入门到实战

protobuf多平台使用

Protobuf 从入门到实战

ProtoBuf入门

# # # ProtoBuf

干货 | protobuf-c之嵌入式平台使用