美文网首页
Android反序列化方案

Android反序列化方案

作者: ZoranLee | 来源:发表于2022-07-12 14:20 被阅读0次

    xml解析、Gson、protobuf、flatbuffers具体实践对比

    情境

    Android大文件反序列化

    性能简单对比

    解析类型 文件大小(样本数据量一致) 反序列化时间具体 解析类型 传送门
    xml解析 1.8M 159ms sax/pull解析 https://developer.android.com/reference/javax/xml/parsers/SAXParserFactoryhttps://developer.android.com/reference/org/xmlpull/v1/XmlPullParser
    Json反序列化 1.8M 79ms Gson https://github.com/google/gson
    ProtoBuffer反序列化 1.5M(转成二进制文件会变小) 142ms ProtoBuffer https://developers.google.com/protocol-buffers
    wire 1.5M 140ms Dinosaur.ADAPTER.decode https://square.github.io/wire/
    flatbuffers 反序列化 1.6M(比ProtoBuffer二进制文件稍大一点) 2ms flatbuffers https://github.com/google/flatbuffers
    解析类型 支持文件类型 传送门
    FastJson2 JSON、JSONB https://github.com/alibaba/fastjson2
    Gson (2.9.0) JSON、Proto https://github.com/google/gson
    文件类型 链接 性能数据
    JSONB https://alibaba.github.io/fastjson2/jsonb_format_cn https://alibaba.github.io/fastjson2/benchmark_cn
    Proto https://developers.google.com/protocol-buffers/docs/tutorials https://tech.meituan.com/2015/02/26/serialization-vs-deserialization.html

    以下数据来自https://code.google.com/p/thrift-protobuf-compare/wiki/Benchmarking

    解析性能

    image.png

    序列化之空间开销:

    image.png
    解析类型 支持文件类型 compiler 生成命令 依赖
    ProtoBuffer proto https://github.com/protocolbuffers/protobuf#protocol-compiler-installation protoc -I=SRC_DIR --java_out=DST_DIR $SRC_DIR/addressbook.proto implementation 'com.google.protobuf:protobuf-java:3.21.2'
    Wire proto https://square.github.io/wire/ https://github.com/square/wire/blob/master/wire-library/docs/wire_compiler.md api "com.squareup.wire:wire-runtime:4.4.0"
    flatbuffers fbs https://github.com/google/flatbuffers/releases flatc -o ./ --java animal.fbs implementation 'com.google.flatbuffers:flatbuffers-java:2.0.0'

    小结

    • protobuf Java版反序列化比xml解析稍好一些,比Gson反序列化耗时要长

    • wire
      提供了Gradle插件,能根据proto schema文件直接生成Java文件。
      square公司提供的api很符合开发者思维,使用起来比protoBuffer顺手多了,很愉快的就完成转换
      根据相关文件、序列化、反序列化操作,其性能表现也与等量xml解析不相伯仲,目测只是使用方式变了,具体实现方式还是protobuf那一套。

    • flatbuffers【Java版】 2ms
      仅仅为2ms的解析时间,后续看了它实现的原理,就不能称为解析时间了,因为它不需要解析。
      后续我又将文件大小扩容到92M,读取速度仅为47ms,这样还比1.8M的Gson解析快一倍

    Flatbuffers

    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();
            }
    

    相关文章

      网友评论

          本文标题:Android反序列化方案

          本文链接:https://www.haomeiwen.com/subject/zszobrtx.html