protobuf的使用和原理
2016-03-20 10:50
363 查看
Protocol Buffers 是一种轻便高效的结构化数据存储格式,可以用于结构化数据串行化,很适合做数据存储或 RPC 数据交换格式。它可用于通讯协议、数据存储等领域的语言无关、平台无关、可扩展的序列化结构数据格式,说白了其实就是用来传输数据的,本文介绍用Java实现的protocolBuffer是如何传输数据的
protobuf的编译器和运行时的java环境可以去官网或者这里去下载http://download.csdn.net/detail/u010031673/9464262 一定要保证编译器的版本和java环境的版本。
简单的protobuf例子
新建一个.proto文件,内容如下
required:不可空字段(在序列化传输之前一定要设置值)
optional:可空字段(在序列化传输之前可以不设置值)
repeated:可重复字段,和java中的数组对应
protobuf和高级语言中数据类型的对应关系如下
![](https://img-blog.csdn.net/20160320092425358?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
每一个字段都有一个唯一标识,这个标识的作用是在格式化成二进制的消息中识别定义的每一个字段,这个标识一旦定义后就不应该再进行修改
protobuf可以为字段设置默认值,格式如下
protobuf中同样支持在一个类中引用一个自定义的消息类型
将上面这个文件定义为test.proto文件,放到这个目录下(可以是任意目录)
![](https://img-blog.csdn.net/20160320094743922?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
打开DOS命令行窗口进入D: 输入如下命令
![](https://img-blog.csdn.net/20160320094857955?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
会在当前目录下生成一个目录结构为包层次目录结构的文件,文件名称为.proto文件中定义的名称
![](https://img-blog.csdn.net/20160320095324056?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
新建一个maven项目(普通项目也可以),将生成的文件复制到该项目下,生成proto文件时一定要保证定义的包结构和proto文件放在项目中的位置保持一致,项目结构如下:
![](https://img-blog.csdn.net/20160320095728620?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
在pom文件中引入如下依赖,如果不是maven项目则自行引入jar包,jar包在上面的下载链接中有
下面介绍如何在程序中使用protobuf
SendMessageDemo:
![](https://img-blog.csdn.net/20160320104812876?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
这个例子本身并无意义,但只要稍加修改就可以将它变成更加有用的程序。比如将磁盘替换为网络 socket,那么就可以实现基于网络的数据交换任务。而存储和交换正是 Protobuf 最有效的应用领域
protobuf的编译器和运行时的java环境可以去官网或者这里去下载http://download.csdn.net/detail/u010031673/9464262 一定要保证编译器的版本和java环境的版本。
简单的protobuf例子
新建一个.proto文件,内容如下
package com.klq.net.protobuf; option java_outer_classname = "AddressBookProtos"; message Person { required string name = 1; required int32 id = 2; optional string email = 3; }属性有三种可选类型
required:不可空字段(在序列化传输之前一定要设置值)
optional:可空字段(在序列化传输之前可以不设置值)
repeated:可重复字段,和java中的数组对应
protobuf和高级语言中数据类型的对应关系如下
每一个字段都有一个唯一标识,这个标识的作用是在格式化成二进制的消息中识别定义的每一个字段,这个标识一旦定义后就不应该再进行修改
protobuf可以为字段设置默认值,格式如下
required int32 id=2 [default=10];我们还可以在protobuf文件中定义枚举类和内部类
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; }
protobuf中同样支持在一个类中引用一个自定义的消息类型
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;
}
将上面这个文件定义为test.proto文件,放到这个目录下(可以是任意目录)
打开DOS命令行窗口进入D: 输入如下命令
会在当前目录下生成一个目录结构为包层次目录结构的文件,文件名称为.proto文件中定义的名称
新建一个maven项目(普通项目也可以),将生成的文件复制到该项目下,生成proto文件时一定要保证定义的包结构和proto文件放在项目中的位置保持一致,项目结构如下:
在pom文件中引入如下依赖,如果不是maven项目则自行引入jar包,jar包在上面的下载链接中有
<dependency> <groupId>com.google.protobuf</groupId> <artifactId>protobuf-java</artifactId> <version>2.6.1</version> </dependency>
下面介绍如何在程序中使用protobuf
SendMessageDemo:
package com.klq.net.protobuf; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.sql.Savepoint; import com.klq.net.protobuf.AddressBookProtos.AddressBook; import com.klq.net.protobuf.AddressBookProtos.Person; public class SendMessageDemo { private static File addressBookFile; public static void main(String[] args) { //定义一个Person对象Person.newBuilder(),并使用一个 //引用Person.Builder来指向它 Person.Builder person = Person.newBuilder(); person.setName("Hugh Jackman"); person.setId(188); person.setEmail("10086@163.com"); //创建一个PhoneNumber内部类对象 Person.PhoneNumber.Builder phoneNumber1= Person.PhoneNumber.newBuilder(); phoneNumber1.setNumber("1008611"); phoneNumber1.setType(Person.PhoneType.MOBILE); person.addPhone(phoneNumber1); Person.PhoneNumber.Builder phoneNumber2= Person.PhoneNumber.newBuilder(); phoneNumber2.setNumber("10010"); phoneNumber2.setType(Person.PhoneType.MOBILE); person.addPhone(phoneNumber2); AddressBook.Builder addressBook= AddressBook.newBuilder(); addressBook.addPerson(person); SendMessageDemo demo = new SendMessageDemo(); demo.addressBookFile=new File("addressBook.txt"); demo.saveToFile(addressBookFile, addressBook); } private void saveToFile(File file,AddressBook.Builder addressBook){ byte[] target = addressBook.build().toByteArray(); try { OutputStream fos = new FileOutputStream(file); fos.write(target); }catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }ReceiveMessageDemo:
package com.klq.net.protobuf; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import com.google.protobuf.InvalidProtocolBufferException; import com.klq.net.protobuf.AddressBookProtos.AddressBook; import com.klq.net.protobuf.AddressBookProtos.Person; import com.klq.net.protobuf.AddressBookProtos.Person.PhoneNumber; public class ReceiveMessageDemo { private static File addressBookFile=new File("addressBook.txt"); public static void main(String[] args) { ReceiveMessageDemo rmd = new ReceiveMessageDemo(); try { InputStream io = new FileInputStream(addressBookFile); AddressBook addressBook=AddressBookProtos.AddressBook.parseFrom(io); for(Person p:addressBook.getPersonList()){ System.out.println("name:"+p.getName()); System.out.println("id:"+p.getId()); System.out.println("email:"+p.getEmail()); for(PhoneNumber pn:p.getPhoneList()){ System.out.println("person's phoneNumer:"+pn.getNumber()); System.out.println("person's phoneNumerType:"+pn.getType()); } } // System.out.println(addressBook.toString()); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } }目录结构如下:
这个例子本身并无意义,但只要稍加修改就可以将它变成更加有用的程序。比如将磁盘替换为网络 socket,那么就可以实现基于网络的数据交换任务。而存储和交换正是 Protobuf 最有效的应用领域
相关文章推荐
- 端口详解(3)-源端口
- 二级域名原理以及程序
- 华为交换机的后缀详解
- DLL(Dynamic Linkable Library) 详解说明
- rudy 重载方法 详解
- 一根网线内的8根线哪4根是传输数据的,哪四根是防干扰的
- TCP三次握手及原理
- jQuery中的pushStack实现原理和应用实例
- sqlserver索引的原理及索引建立的注意事项小结
- php中的ini配置原理详解
- jquery原理以及学习技巧介绍
- 留言板翻页的实现详解
- PHP strtotime函数用法、实现原理和源码分析
- Base64编码解码原理及C#编程实例
- IsPostBack原理的介绍
- 前端轻量级MVC框架CanJS详解
- JS event使用方法详解
- jQuery中noconflict函数的实现原理分解
- 无边框窗口代码详解
- MySQL主从同步原理介绍