第一次听说这个东西,是15年一位业内的同事告诉我的。不过一直没有机会用到过这种格式。一般的公司还是用 xml 、 json。而在移动端还是 json为主流。
不过,听说过这个东西总比没有听说过好,今天就借用网上找的文章给大家发一篇博客。
什么是protobuf
百度百科:protocolbuffer是google 的一种数据交换的格式,它独立于语言,独立于平台。google 提供了三种语言的实现:java、c++ 和 python,每一种实现都包含了相应语言的编译器以及库文件。由于它是一种二进制的格式,比使用 xml 进行数据交换快许多。可以把它用于分布式应用之间的数据通信或者异构环境下的数据交换。作为一种效率和兼容性都很优秀的二进制数据传输格式,可以用于诸如网络传输、配置文件、数据存储等诸多领域。
ProtocolBuffer是用于结构化数据串行化的灵活、高效、自动的方法,有如XML,JSON,不过它更小、更快、也更简单。你可以定义自己的数据结构,然后使用代码生成器生成的代码来读写这个数据结构。你甚至可以在无需重新部署程序的情况下更新数据结构。
protobuf全称Google Protocol Buffers,是google开发的的一套用于数据存储,网络通信时用于协议编解码的工具库。它和XML或者JSON差不多,也就是把某种数据结构的信息,以某种格式(XML,JSON)保存起来,protobuf与XML和JSON不同在于,protobuf是基于二进制的。主要用于数据存储、传输协议格式等场合。
为什么使用protobuf
为什么不使用json和xml?
ProtocolBuffer拥有多项比XML更高级的串行化结构数据的特性,ProtocolBuffer:
- 更简单
- 小3-10倍
- 快20-100倍
- 更少的歧义
- 可以方便的生成数据存取类
官方给出的对比测试数据:
长度
时间
protobuf的占用空间少和传输时间少的原理是什么
这里我们看下IBM技术论坛里面的讲解, Google Protocol Buffer 的使用和原理
如何使用protobuf
- protobuf官方给出的是支持三种语言,java、c++、Python,这里我们使用java语言来演示它的使用demo
准备工作
.protobuf:我使用的是protobuf-java-2.4.1版本的protobuf
windows下,需要下载两个包:
protobuf-2.6.1.tar.bz2 (protobuf所有的源码都在里面,用它进行编译成lib库)
protoc-2.6.1-win32.zip(内涵protoc.exe,用来把proto文件编译成目标语言(C++,Java,Python)的文本,是google protobuf定义的格式。其实这个文件不是必须的,编译protobuf-2.6.1.tar.bz2的时候会生成这个exe)
去官网下载protobuf的source code和编译工具:https://developers.google.com/protocol-buffers/docs/downloads
这两个版本必须保持一致
这里我们将下载好的文件放在:E:\proto
-
编写proto文件
package tutorial; option java_package = "com.example.tutorial"; option java_outer_classname = "AddressBookProtos"; message Person { required string name = 1; required int32 id = 2; optional string email = 3; enum PhoneType { MOBILE = 0; HOME = 1; WORK = 2; } message PhoneNumber { required string number = 1; optional PhoneType type = 2 [default = HOME]; } repeated PhoneNumber phone = 4; } message AddressBook { repeated Person person = 1; }
-
将文件与prtoc.exe放在同一层目录下
-
执行编译命令:
E:\proto>protoc.exe --java_out=./ addressbook.proto
- 将生成的AddressBookProtos.java拷贝到对应的项目中,将protobuf-java-2.4.1.jar考到对应的项目中,开始进行demo开发
- 案例:
客户端:
Person.Builder person = Person.newBuilder();
person.setName("张三");
person.setId(1);
person.setEmail("123@126.com");
PhoneNumber.Builder phoneNumber1 = PhoneNumber.newBuilder().setNumber("13838383838").setType(PhoneType.MOBILE);
PhoneNumber.Builder phoneNumber2 = PhoneNumber.newBuilder().setNumber("110").setType(PhoneType.WORK);
person.addPhone(phoneNumber1);
person.addPhone(phoneNumber2);
Person build = person.build();
byte[] mydata = build.toByteArray();
服务器端:
Person person = Person.parseFrom(msgbody);
System.out.println(person.getId());
System.out.println(person.getName());
System.out.println(person.getEmail());
System.out.println(person.getPhoneCount());
System.out.println(person.getPhone(0).getNumber()+","+person.getPhone(0).getType());
List<PhoneNumber> phoneList = person.getPhoneList();
for (PhoneNumber phoneNumber : phoneList) {
System.out.println(phoneNumber.getNumber()+","+phoneNumber.getType());
}
proc文件定义
options(包名,类名)
java_package是文件级别的选项,通过指定该选项可以让生成Java代码的包名为该选项值,如上例中的Java代码包名为com.example.tutorial与此同时,生成的Java文件也将会自动存放到指定输出目录下的com/example/tutorial与此同时子目录中。如果没有指定该选项,Java的包名则为package关键字指定的名称。
javaouterclassname是文件级别的选项,主要功能是显示的指定生成Java代码的外部类名称。如果没有指定该选项,Java代码的外部类名称为当前文件的文件名部分,同时还要将文件名转换为驼峰格式
关键字 message(消息) enum(枚举)
message:message是消息定义的关键字,等同于是Java中的class。 enum:enum是枚举类型定义的关键字,等同于Java中的enum。
修饰符 required(必需的),repeated(可重复),optional(可选)
限定符(required/optional/repeated)的基本规则。
1. 在每个消息中必须至少留有一个required类型的字段。
2. 每个消息中可以包含0个或多个optional类型的字段。
3. repeated表示的字段可以包含0个或多个数据。需要说明的是,这一点有别于Java中的数组,因为后者中的数组必须包含至少一个元素。
4. 如果打算在原有消息协议中添加新的字段,同时还要保证老版本的程序能够正常读取或写入,那么对于新添加的字段必须是optional或repeated。道理非常简单,老版本程序无法读取或写入新增的required限定符的字段。
数据类型
谷歌官方地址:https://developers.google.com/protocol-buffers/docs/javatutorial
jar包2.0-2.6下载地址:http://grepcode.com/project/repo1.maven.org/maven2/com.google.protobuf/protobuf-java/
github地址:https://github.com/google/protobuf