通过Java测试JSON和协议缓冲区的传输文件大小
我相信大家都知道JSON是什么。如果他们不知道,那就真的完了。转到GOOGLE。这里就不介绍什么了。Protobuffer,你可能很少听说过,但如果说是GOOGLE负责的话,相信大家都会有兴趣尝试一下。毕竟,GOOGLE出口,而且大部分都是精品。Protobuffer是一种类似于JSON的传输协议。其实不能叫协议,只是数据传输的事情。JSON和JSON有什么区别?跨语言,这是它的优势之一。它附带了一个编译器protocol,可以编译成JAVA、python和C代码。暂时只有这三个代码,其他的都可以直接使用,不用写其他任何代码。甚至那些被分析过的都被带来了。JSON当然是跨语言的,但是这种跨语言是基于编码的。如果你想了解更多,可以去看看:https://developers.google.com/protocol-buffers/docs/overview,我们不多说了,直接看为什么要对比protobuffer(以下简称GPB)和JSON。1.JSON有一定的格式,以字符的形式存在,所以在数据量上还有压缩的空间。然而,当GPB有大量数据时,空间比JSON小得多。我们可以在后面看到这个例子。2.JSON库的效率差别很大,jackson库和GSON的差别在5-10左右(这个只测试过一次,如有错误请轻点)。但是,只需要一个GPB,多个库之间没有区别。当然,这一点只是编出来的,可以忽略。说话便宜,给我看看代码就行了。在程序世界里,代码永远是王道,所以我们直接进入代码。在加载代码之前,每个人都应该下载protobuffer,这里是:https://github.com/google/protobuf.
1.首先,GPB是一个需要有类似类定义的文件,叫做proto文件。我们以学生和老师为例:我们有以下两个文件:student.proto
option java _ package=' com.shun选项Java _ outer _ class name=' StudentProto ';消息Student {必填项int 32 id=1;可选字符串名称=2;可选int 32 age=3;}/span教师. proto
导入“student . proto”;option java _ package=' com.shun选项Java _ outer _ name=' Ticheerproto ';消息教师{必需的int 32 id=1;可选字符串名称=2;重复学生学生_列表=3;}/span在这里我们遇到了一些奇怪的事情:import、int32、repated、required、optional、option等。让我们一个一个来:1)导入意味着引入其他proto文件;2)必选,可选表示字段是否可选,这决定了如果字段有值,protobuffer会做什么。如果标记了“必需”,但在处理过程中没有在此字段中传递任何值,将会报告错误。如果标记了可选,那么如果没有传递值,就不会有问题。3)我相信重复应该是可以理解的,即是否重复,类似于JAVA中的列表。4)消息相当于类。5)option表示option,其中java_package表示生成java代码时使用的包名,java_outer_classname为类名。请注意,此类名不能与以下消息中的类名相同。有关其他选项和相关类型,请访问官方文档。2.我们能用这些文件做什么?记得上面下载的编译器。提取后,我们得到了一个protoc.exe,当然是在窗户下面。我没有得到任何其他系统。感兴趣的学生去翻来覆去。将其添加到path中(添加与否,只是不方便),然后我们就可以从上面的文件中生成我们需要的类文件。proto-Java _ out==存储源代码的路径-proto _ path=的路径-proto _ path=proto specific file-proto _ path指定的是proto文件的文件夹路径,不是单个文件,主要用于搜索导入文件,如果我需要把源代码放在D: \ ProtobufferVsJson \ src中,我的proto文件存储在D:\protoFiles中,那么我的编译命令是:
protocol-Java _ out=d : \ proto buffersjson \ src d : \ proto files \ teacher . proto d : \ proto files \ student . proto注意,对于这里的最后一个文件,我们需要指定所有需要编译的文件,我们可以看到编译后生成的文件。代码不会发布,太多了。你可以私下看看。代码中有很多Builders。相信大家看了就知道是建造者模式。现在,您可以将代码粘贴到项目中。当然有很多错误。还记得我们之前下载的源代码吗?拉开拉链,别手软。然后找到src/main/java/并把它们复制到你的项目中。当然,你也可以用ant或者maven来编译它们,但是我对这两个东西并不熟悉,所以不会出丑。我仍然习惯于直接将它们复制到项目中。
代码错误,哈哈,正常。出于某种原因,GOOGLE不得不给我们留下这样一个漏洞。回到protobuffer目录中的\java,看到一个readme.txt,找到一句话:
看,我感觉这个代码会有点奇怪,好像是错的。不管怎样,我没明白。我的命令是:
span style=' font-size : 16px;'protocol-Java _ out==proto文件的路径(这里是descriptor.proto文件的路径)/span仍然是放置代码的地方。执行之后,我们可以看到代码中的错误都消失了。3.下一步当然是测试。我们先来做GPB的写作测试:
打包。顺。测试;导入Java。io。文件输出流;导入Java。io。ioexception导入Java。乌提尔。ArrayList导入Java。乌提尔。列表;导入com。顺。studentproto。学生;导入com。顺。教师协议。老师;公共类原型{公共静态void main(String[]args)引发IOException {学生.builder studbuilder=学生。new builder();斯图建设者。setage(25);斯图建设者。SetID(11);斯图建设者。setname(' shun ');//构造list student builder list=new ArrayList student();stubuilderlist。添加(stubuilder。build());老师建设者teaBuilder=老师。new builder();teaBuilder。SetID(1);TeaBuilder。SetName(' TestTea ');泡茶师。addallstudentlist(studbuilderlist);//把gpb写入到文件文件输出流fos=新文件输出流(' c : \ \ user \ \ shun \ \ Desktop \ \ test \ \ test。proto out’);teaBuilder.build().写入(fos);福斯。close();} }/span我们去看看文件,如无意外,应该是生成了的。生成了之后,我们肯定要读回它的。
打包。顺。测试;导入Java。io。FileInputStream导入Java。io。FileNotFoundException导入Java。io。ioexception导入com。顺。studentproto。学生;导入com。顺。教师协议。老师;公共类protreadtest { public static void main(String[]args)引发FileNotFoundException,IOException {教师教师=测试仪。ParseFrom(new FileInputStream(' c : \ \ user \ \ shun \ \ Desktop \ \ Test \ \ Test。proto out’);系统。出去。println('教师id : '教师。getid()',名称: '老师。getname());对于(学生stu :教师。getstudentlistlist()){ system。出去。println('学生证: '学生。getid()',Name:' stu.getName()',age : ' stu。getage());} } }/span代码很简单,因为GPB生成的代码都帮我们完成了。上面知道基本的用法了,我们重点来关注GPB跟JSON生成文件大小的区别,JSON的详细代码我这里就不贴了,之后会贴出示例,大家有兴趣可以下载。这里我们用Gson来解析JSON,下面只给出对象转换成JSON后写出文件的代码:两个类学生和教师的基本定义就不弄了,大家随意就行,代码如下:
打包。顺。测试;导入Java。io。FileWriter导入Java。io。ioexception导入Java。乌提尔。ArrayList导入Java。乌提尔。列表;进口。com。谷歌。gson。Gson导入com。顺。学生;导入com。顺。老师;公共类GsonWriteTest { public static void main(String[]args)引发IOException { Student stu=new Student();stu.setAge(25岁);斯图。setid(22);斯图。setname(' shun ');list student list=new ArrayList student();斯图名单。添加(stu);教师教师=新教师();老师。setid(22);老师。setname(' shun ');老师。setstudlist(studlist);字符串结果=新Gson().toJson(老师);文件编写器fw=新文件编写器(' c : \ \用户\ \顺\ \桌面\ \测试\ \ JSON ');fw.write(结果);fw。close();} }/span接下来正式进入我们的真正测试代码了,前面我们只是在列表中放入一个对象,接下来,我们依次测试100,1000,10000,100000,1000000,5000000这几个数量的GPB和JSON生成的文件大小。改进一下之前的GPB代码,让它生成不同数量的列表,再生成文件:
打包。顺。测试;导入Java。io。文件输出流;导入Java。io。ioexception导入Java。乌提尔。ArrayList导入Java。乌提尔。列表;导入com。顺。studentproto。学生;导入com。顺。教师协议。老师;公共类protoittest { public static final int SIZE=100;公共静态void main(字符串[]参数)引发IOException { //构造list student builder list=new ArrayList student();for(int I=0;我尺寸;I){ 0学生建设者学生建设者=学生。new builder();斯图建设者。setage(25);斯图建设者。SetID(11);斯图建设者。setname(' shun ');stubuilderlist。添加(stubuilder。build());}老师建设者teaBuilder=老师。new builder();teaBuilder。SetID(1);TeaBuilder。SetName(' TestTea ');泡茶师。addallstudentlist(studbuilderlist);//把gpb写入到文件file output stream fos=new file output stream(' c : \ \ user \ \ shun \ \ Desktop \ \ test \ \ proto-' SIZE);teaBuilder.build().写入(fos);福斯。close();} }/span这里的大小依次改成我们上面据说的测试数,可以得到如下:
然后我们再看看JSON的测试代码:
打包。顺。测试;导入Java。io。FileWriter导入Java。io。ioexception导入Java。乌提尔。ArrayList导入Java。乌提尔。列表;进口。com。谷歌。gson。Gson导入com。顺。学生;导入com。顺。老师;公共类GsonWriteTest { public static final int SIZE=100;公共静态void main(String[]args)引发IOException { listsudent stu list=new ArrayList student();for(int I=0;我尺寸;I){ 0学生斯图=新学生();stu.setAge(25岁);斯图。setid(22);斯图。setname(' shun ');学生名单。添加(stu);}教师教师=新教师();老师。setid(22);老师。setname(' shun ');老师。setstudlist(studlist);字符串结果=新Gson().toJson(老师);文件编写器fw=新文件编写器(' c : \ \用户\ \顺\ \桌面\ \测试\ \ JSON ' SIZE);fw.write(结果);fw。close();} }/span同样的方法修改尺寸,并作相应的测试。
可以明显得看到json的文件大小跟GPB的文件大小在数据量慢慢大上去的时候就会有比较大的差别了,JSON明显要大上许多。
上面的表应该可以看得比较清楚了,在大数据的GPB是非常占优势的,但一般情况下客户端和服务端并不会直接进行这么大数据的交互,大数据主要发生在服务器端的传输上,如果你面对需求是每天需要把几百M的日志文件传到另外一台服务器,那么这里GPB可能就能帮你的大忙了
说是深度对比,其实主要对比的是大小方面,时间方面可比性不会太大,也没相差太大。文章中选择的Gson解析器,有兴趣的朋友可以选择杰克逊或者法斯森,又或者其他的,但生成的文件大小是一样的,只是解析时间有区别。
版权声明:通过Java测试JSON和协议缓冲区的传输文件大小是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。