环境: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
- 准备 flatc 的编译工具
- 导入 flatbuffers java库
- 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<String>) {
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:
- 跨平台/语言开发
- JSON解析的效率和内存问题