|
情境
Android大文件解析
1、本次使用1.8M、92M大文件(xml、json格式各一份)作为样本数据
2、二进制文件均是通过Json序列化后的实体Bean生成,
3、依据对应关系,映射成相应的ProtoTypeAdapter(Proto)、Table (flatbuffers)实体,结合output流持久化成文件
性能简单对比
测试数据基于vivo V2080A
不同手机,花费时间量不同
相同手机,不同状态,花费时间量不同
解析时间
xml 【使用SAX、Pull解析】159msjson 【Gson2.9.0】 79ms
- protobuf 【Java版】 142ms
由于对protobuf读取抱有很大的希望,目测对大文件解析会快的飞起
但是实际情况是:protobuf的Java版解析表现并不如Gson,稍好于xml解析
曾经一度怀疑是自己使用的方式有问题,并在官网实例的基础上扩充了数据量,其性能表现也与等量xml解析差不多。
- 插曲:https://square.github.io/wire/
在怀疑自己使用方式的同时,找到了更友好(顺手)的API: wire
square公司提供的api很符合开发者思维,使用起来比protoBuffer顺手多了,很愉快的就完成转换
也实现了相关生成解析操作,其性能表现也与等量xml解析差不多。
由此得出结论:
protobuf 的Java版解析大文件性能一般,不如json
猜测可能c++版会好点(c++我的没试过)
- flatbuffers【Java版】 2ms
由于觉得二进制不应该表现这么差,后续又摸索到flatbuffers这个库 ,
最后验证仅仅为2ms的解析时间,后续看了它实现的原理,就不能称为解析时间了,因为它不需要解析。
后续我又将文件大小扩容到92M,读取速度仅为47ms,这样还比1.8M的Gson解析快一倍
相关链接
Xml 解析
1、https://developer.android.com/reference/javax/xml/parsers/SAXParserFactory
2、https://developer.android.com/reference/org/xmlpull/v1/XmlPullParser
老熟人,不过多介绍了。
Json 解析
Gson
传送门:
- https://github.com/google/gson
1、json格式
2、已经对proto格式进行了支持【工程中文档没写,但是工程中已经有相关示例了】
image.png
能将json文本序列化成二进制proto文件
fastjson
传送门:
https://github.com/alibaba/fastjson 老熟人了,不介绍了
- https://github.com/alibaba/fastjson2 目标是为下一个十年提供一个高性能的JSON库
这个库支持JSONB格式
JSONB格式文档: https://alibaba.github.io/fastjson2/jsonb_format_cnFASTJSON v2性能有了很大提升,具体性能数据看这里:
https://alibaba.github.io/fastjson2/benchmark_cn
有一个弊端:
image.png
只支持android 8.0以上的手机,就不多研究的,有兴趣的可以看看
Protobuf
https://github.com/protocolbuffers/protobuf#protocol-compiler-installation proto文件编译器https://developers.google.com/protocol-buffers 语法使用
- https://square.github.io/wire/
今天主角是Flatbuffers,这个先跳过了
Flatbuffers
https://google.github.io/flatbuffers/
- https://github.com/google/flatbuffers
这个库让人头疼的地方:
1、就是文档很不完善,操作细节全靠摸索
2、文件scheme和proto文件完全不一样
3、数据流使用的是bytebuffer (转字节数组有点坑)
4、文件使用 .fbs ,支持类型:https://google.github.io/flatbuffers/flatbuffers_guide_writing_schema.html
Built-in scalar types are 8 bit: byte (int8), ubyte (uint8), bool 16 bit: short (int16), ushort (uint16) 32 bit: int (int32), uint (uint32), float (float32) 64 bit: long (int64), ulong (uint64), double (float64) Vector of any other type (denoted with [type]). Nesting vectors is not supported, instead you can wrap the inner vector in a table. string, which may only hold UTF-8 or 7-bit ASCII. For other text encodings or general binary data use vectors ([byte] or [ubyte]) instead. References to other tables or structs, enums or unions
5、fbs文件不同语言编译器:虽然文档没说,但是在release页面找到了
https://github.com/google/flatbuffers/releases 我分别下了Mac、Windows的都试过了,没啥问题
6、序列化、持久化
Flatbuffers 具体实现
1、xml.fbs文件,android studio有fbs高亮插件
namespace com.fbs.app.generated;table Menu { type:string; mainmenu:MainmenuDTO;}table MainmenuDTO{ item:[ItemDTO];//数组}table ItemDTO{ code:string; activity:string; iconum:string; icon:string; type:string; extended:string; parentid:string; localUrl:string; authorityHide:string; moreentry:string; id:string; iconUrl:string; homeAuth:string; classX:string; msgtype:string; order:string; appnum:string; packageX:string; textSize:string; business:string; parentflag:string; textPostion:string; navigateNote:string; constructor:string; relationId:string; textColor:string; url:string; authority:string; name:string; textBackground:string; hascontent:string; DefaultLoad:string; menuAuthority:string; ShowTitleLine:string; turnViewType:string;}root_type Menu;
2、根据fbs文件生成java类
下载相关系统平台的编译器,执行
$ flatc -o ./ --java animal.fbs
-o 我指定了当前目录生成,我将flatc配置成了全局变量,可以指定其他目录
--java 生成java文件,也可以指定为kotlin
生成了三个文件:Menu.java MainmenuDTO.java ItemDTO.java
3、根据json Bean生成二进制文件
private void createFlatBuffersFile(Bean bean) {FlatBufferBuilder fb = new FlatBufferBuilder(100);int[] dataArray = new int[bean.menu.mainmenu.item.size()]; for (com.example.locationapplication.Bean.MenuDTO.MainmenuDTO.ItemDTO itemDTO : bean.menu.mainmenu.item) { int itemOffset = ItemDTO.createItemDTO(fb, fb.createString(itemDTO.code), fb.createString(itemDTO.activity), fb.createString(itemDTO.iconum), fb.createString(itemDTO.icon), fb.createString(itemDTO.type), fb.createString(itemDTO.extended), fb.createString(itemDTO.parentid), fb.createString(itemDTO.localUrl), fb.createString(String.valueOf(itemDTO.authorityHide)), fb.createString("" + itemDTO.moreentry), fb.createString(itemDTO.id), fb.createString(itemDTO.iconUrl), fb.createString(itemDTO.homeAuth), fb.createString(itemDTO.classX), fb.createString(itemDTO.msgtype), fb.createString(itemDTO.order + ""), fb.createString(itemDTO.appnum + ""), fb.createString(itemDTO.packageX), fb.createString(itemDTO.textSize + ""), fb.createString(itemDTO.business), fb.createString(itemDTO.parentflag + ""), fb.createString(itemDTO.textPostion), fb.createString(itemDTO.navigateNote), fb.createString(itemDTO.constructor), fb.createString(itemDTO.relationId), fb.createString(itemDTO.textColor), fb.createString(itemDTO.url), fb.createString(itemDTO.authority), fb.createString(itemDTO.name), fb.createString(itemDTO.textBackground), fb.createString(itemDTO.hascontent + ""), fb.createString(itemDTO.defaultLoad + ""), fb.createString(itemDTO.menuAuthority), fb.createString("ShowTitleLine"), fb.createString("turnViewType") ); dataArray[index] = itemOffset; index++; } int itemVector = MainmenuDTO.createItemVector(fb, dataArray); //这个文档没有说明,多试了几个create开头的方法,使用vector可行int mainmenuDTO = MainmenuDTO.createMainmenuDTO(fb, itemVector); int menuOffset = Menu.createMenu(fb, fb.createString(bean.menu.type), mainmenuDTO );fb.finish(menuOffset);//根据文档来的ByteBuffer byteBuffer = fb.dataBuffer(); //到此处已经映射完成outPutTofile(byteBuffer, "/xml_flatbuffer");//打算将文件写入到包名下的files目录下,文件名为xml_flatbuffer} /** * 将解析数据持久化到文本 * @param byteBuffer* @param filename*/private void outPutTofile(ByteBuffer byteBuffer, String filename) {// byte[] array = byteBuffer.array(); 这里有坑,直接取array 反解不出来,之前一直以为是文件存取的问题,后来发现需要使用buf.get(array);的方式,下面是正确的方式 ByteBuffer buf = byteBuffer; byte[] array = new byte[buf.remaining()]; buf.get(array); try { String filePath = getFilesDir() + filename; File file = new File(filePath); if (!file.exists()) { file.createNewFile(); } FileOutputStream fileOutputStream = new FileOutputStream(file); fileOutputStream.write(array); } catch (IOException e) { e.printStackTrace(); } }读取flatbuffers文件
try { File file = new File(getFilesDir() + "/xml_flatbuffer"); RandomAccessFile f = new RandomAccessFile(file, "r"); byte[] data = new byte[(int) f.length()]; f.readFully(data); ByteBuffer bb = ByteBuffer.wrap(data); Menu rootAsMenu1 = Menu.getRootAsMenu(bb);//反解结束 f.close(); } catch (IOException e) { e.printStackTrace(); } |
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
×
|