[Note] 2021-04-21FlatBuffers

环境:macOS

一 使用FlatBuffers序列化数据

参考 https://blog.csdn.net/guotianqing/article/details/100097909

1.1 序列化

场景:跨平台/语言(C<=>Java),跨进程,持久化,网络传输(RMI传输对象等)
概念:数据结构/对象 => 二进制串 (反序列化:数据结构/对象 <= 二进制)
性能维度:通用性(跨平台/语言),空间,时间,兼容/拓展性,安全/访问限制
序列化工具: XML, SOAP, Protobuf, FlatBuffers, SBE(Simple Binary Encoding), Cap'n Proto

1.2 FlatBuffers

1.2.1 优点:

  • 使用简单,定义协议文件(schema)、编译成源码、操作数据
  • 效率高,数据在缓冲区内都是平整的,可以直接访问
  • 使用便利,协议文件设计好后可以发布,可以随时往Table里面添加或者删除成员

1.2.2 缺点:

  • 效率高的同时导致cpu资源占用相对较高
  • 传输的数据可能比对数据进行压缩后再传输要大
  • 打包后的FlatBuffers中的矢量数据不能随意修改(一般打包后直接发送,没有这个需求)
  • FlatBuffers传输的数据没有JSON、XML和HTML那么直观

1.2.3 数据结构

  • struct
    Struct 标量,修改时需要全量编译;优点是访问速度快,占用内存少。
  • Table
    Table 矢量,可以增删,删除时定义为deprecated(向后兼容)
  • root_type
    是一个顶级类型。
  • union
    联合

标量都是直接写到缓冲区去的,所有的矢量需要先写到缓冲区,然后获得偏移量(32位),然后再把偏移量写到适当的结构中,每个矢量都离不开一个偏移量。

1.2.4 数据类型

  • 标量
    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)
    括号内的名字是它前面类型的别名,两者使用方式等价。
  • 矢量类型包括:
    向量,使用[type]形式
    string,仅支持UTF-8或者7位ASCII码,其他编码或者通常的二进制数据可以使用向量[byte]/[ubyte]替代
    引用其他tables/structs/enums/unions

1.2.5 使用步骤

  • 编写 schema 文件,描述数据结构和接口定义。
  • 用 flatc 编译,生成相应语言的代码文件。
  • 使用 FlatBuffers 支持的语言(如C ++,Java等)生成的文件进行开发。

1.2.6 横向对比

非扁平化(多层键值对结构)数据和等效的扁平化(多维数组)数据* 数据量小、快速迭代、包含大量字符串数据,使用JSON,方便快捷;

  • 数据量小、接口稳定、静态语言主导、多语言协作、集成IDL、依赖gPRC,考虑 protocol buffers。
  • 数据量大、接口稳定、静态语言主导、集成IDL、数据无法扁平化,考虑 flat buffers。
  • 数据量大、快速迭代、性能要求高、数据可以扁平化,不希望使用重量级工具或修改工程结构,考虑DIMBIN。

二 Android 使用 FlatBuffers

  1. 准备 flatc 的编译工具
  2. 导入 flatbuffers java库
  3. FlatBufferBuilder 的使用

2.1 准备 flatc 的编译工具

下载编译 FlatBuffers

  • 使用 homebrew 进行下载:
    brew install flatBuffer
  • 或者下载源码进行编译:
    https://github.com/google/flatbuffers/releases
$ cd flatbuffers-1.12.0
$ cmake .
$ make 
$ make install
$ flatc --version

2.3 导入 flatbuffers java库

  • Maven 导入 implementation 'com.google.flatbuffers:flatbuffers-java:1.12.0'
  • 或者源码导入为模块 https://github.com/google/flatbuffers/tree/master/java/com/google/flatbuffers
    然后进行依赖 implementation project(path: ':flatbuffers')

2.4 FlatBufferBuilder 的简单使用

Kotlin main

  • 创建 .fbs


    image.png
  • 测试代码

    fun onClickMainBtn(v: View?) {}

    companion object {
        @JvmStatic
        fun main(args: Array) {
            val fb = FlatBufferBuilder(1024)
            val userOffsetId1 = User.createUser(fb, 41L, fb.createString("haha"), fb.createString("man"))
            val userOffsetId2 = User.createUser(fb, 42L, fb.createString("hiahia"), fb.createString("woman"))

            val usersIds = intArrayOf(userOffsetId1, userOffsetId2)
            val itemsId = RootType.createItemsVector(fb, usersIds)
            val rootTypeId = RootType.createRootType(fb, itemsId)
            // RootType.finishRootTypeBuffer(fb, rootTypeId)
            fb.finish(rootTypeId)
            // write to file
            val file = saveFbToTestFile(fb)
            // read from file
            val bb = ByteBuffer.wrap(file.readBytes())
            // make root type object
            val rRootType = RootType.getRootAsRootType(bb)
            for (i in 0 until rRootType.itemsLength()) {
                val rUser = rRootType.items(i)
                println("${rUser.id()}, ${rUser.name()}, ${rUser.gender()}")
            }
        }

        private fun saveFbToTestFile(fb: FlatBufferBuilder): File {
            val file = File("/Users/lunix/Desktop/flatc_test.txt")
            if (file.exists()) {
                file.delete()
            }
            file.createNewFile()
            file.outputStream().write(fb.dataBuffer().array(), fb.dataBuffer().position(), fb.offset())
            return file
        }
    }

最后

基于效率和性能问题,项目慢慢使用 FlatBuffers:

  1. 跨平台/语言开发
  2. JSON解析的效率和内存问题

你可能感兴趣的:([Note] 2021-04-21FlatBuffers)