protobuf(Google Protocol Buffers)是Google提供一个具有高效的协议数据交换格式工具库(类似Json),但相比于Json,Protobuf有更高的转化效率,时间效率和空间效率都是JSON的3-5倍。后面将会有简单的demo对于这两种格式的数据转化效率的对比。但这个库目前使用还不是太流行,据说谷歌内部很多产品都有使用。
Protobuf的优点
1,性能好,效率高
2,代码生成机制,数据解析类自动生成
3,支持向后兼容和向前兼容
4,支持多种编程语言(java,c++,python)
可用来做什么?
Protobuf可替代Json,支持Java、C++、Python等语言,简单好用还节省内存流量,可利用Protobuf进行改造,替换原有的Json或者XML存储方式进一步提升性能。还可用在RPC远程过程调用,及客户端、服务器端通信和数据交换。
Xml、Json是目前常用的数据交换格式,它们直接使用字段名称维护序列化后类实例中字段与数据之间的映射关系,一般用字符串的形式保存在序列化后的字节流中。消息和消息的定义相对独立,可读性较好。但序列化后的数据字节很大,序列化和反序列化的时间较长,数据传输效率不高。
Protobuf和Xml、Json序列化的方式不同,采用了二进制字节的序列化方式,用字段索引和字段类型通过算法计算得到字段之前的关系映射,从而达到更高的时间效率和空间效率,特别适合对数据大小和传输速率比较敏感的场合使用。
protobuf转换过的二进制文件具有:
空间效率
Json:107个字节
Protobuf:32个字节
时间效率
Json序列化: 1ms , 反序列化:0ms
Protobuf 序列化: 0ms 反序列化:0ms
将public List<Phone> list和repeated PhoneInfo phoneInfoList =3;都赋值为1000个PhoneInfo
空间效率
Json:4206个字节
Protobuf:1332个字节
时间效率
Json序列化: 4ms , 反序列化:1ms
Protobuf 序列化: 1ms 反序列化:0ms
优点:通过以上的时间效率和空间效率,可以看出protobuf的空间效率是JSON的2-5倍,时间效率要高,对于数据大小敏感,传输效率高的模块可以采用protobuf库。
缺点:消息结构可读性不高,序列化后的字节序列为二进制序列不能简单的分析有效性;目前使用不广泛,只支持java,C++和Python;
使用:
1.首先要在adroid stdio工程根路径下,就是和settings.gradle在同一级目录的build.gradle文件中添加protobuf插件classpath配置。
dependencies { classpath 'com.android.tools.build:gradle:3.0.1' classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.2'
2.在app中的build.gradle添加两个protobuf依赖库:protobuf-java和protoc(如图:app模块中添加protobuf依赖库.png)。protobuf-java是用来处理java代码的,protoc是处理C或者C++代码的。
apply plugin: 'com.google.protobuf'
implementation 'com.google.protobuf:protobuf-java:3.1.0' implementation 'com.google.protobuf:protoc:3.1.0'
3.接着还需要在build.gradle的“android { }”中进行配置自动生成代码的sourceSets目录路径。
sourceSets { main { java { srcDir 'src/main/java' } proto { srcDir 'src/main/proto' include '**/*.proto' } } }
3-1.自动生成的java资源路径:srcDir 'src/main/java'
3-2. 自动生成的proto资源路径:srcDir 'src/main/proto' 和包括后缀为.proto的文件。
//构建task protobuf { protoc { artifact = 'com.google.protobuf:protoc:3.1.0' } generateProtoTasks { all().each { task -> task.builtins { remove java } task.builtins { java {} // Add cpp output without any option. // DO NOT omit the braces if you want this builtin to be added. cpp {} } } } //生成目录 generatedFilesBaseDir = "$projectDir/src/generated" }
4.接下来,在配置的指定位置,即“src/main/”的路径下创建名字为“proto”的文件夹。在“proto”路径下创建.proto为后缀的文件再写上proto格式的代码。
点击“Sync”同步按钮,同步整个工程,protobuf的java代码就会自动生成了,不过生成的是在app/src/genarated文件夹下。使用时
直接import引用过来即可。
举例,一个测试的小demo:
*.proto文件如下:
读写测试demo:
package com.example.yang.myapplication.protobuf; import com.yangyongzhen.bean.Testpro; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; public class Testprotobuf { public static final String FILE_NAME_READ="testpro.txt"; public static final String FILE_NAME_WRITE="testpro1.txt"; public static void main(String[] args) throws IOException { System.out.println("protobuf test:"); //写测试 Testpro.response.Builder respb = Testpro.response.newBuilder(); respb.setLedOn(10); respb.setNodeId("12345"); respb.setParentId("67890"); respb.setUuid("987654321"); Testpro.response resp = respb.build(); File file=new File(FILE_NAME_WRITE); FileOutputStream outputStream = new FileOutputStream(file); resp.writeTo(outputStream); //读测试 File file1=new File(FILE_NAME_READ); FileInputStream inputStream = new FileInputStream(file1); Testpro.response resp1 = Testpro.response.parseFrom(inputStream); int t = resp1.getLedOn(); System.out.println(t); String str = resp1.getNodeId(); System.out.println(str); str = resp1.getParentId(); System.out.println(str); str = resp1.getUuid(); System.out.println(str); } }
输出结果:
protobuf test:
1
5149013220584027
5149013108519750
121212121