環(huán)境:macOS
一 使用FlatBuffers序列化數(shù)據(jù)
參考 https://blog.csdn.net/guotianqing/article/details/100097909
1.1 序列化
場(chǎng)景:跨平臺(tái)/語(yǔ)言(C<=>Java),跨進(jìn)程,持久化,網(wǎng)絡(luò)傳輸(RMI傳輸對(duì)象等)
概念:數(shù)據(jù)結(jié)構(gòu)/對(duì)象 => 二進(jìn)制串 (反序列化:數(shù)據(jù)結(jié)構(gòu)/對(duì)象 <= 二進(jìn)制)
性能維度:通用性(跨平臺(tái)/語(yǔ)言),空間,時(shí)間,兼容/拓展性,安全/訪(fǎng)問(wèn)限制
序列化工具: XML, SOAP, Protobuf, FlatBuffers, SBE(Simple Binary Encoding), Cap'n Proto
1.2 FlatBuffers
1.2.1 優(yōu)點(diǎn):
- 使用簡(jiǎn)單,定義協(xié)議文件(schema)、編譯成源碼、操作數(shù)據(jù)
- 效率高,數(shù)據(jù)在緩沖區(qū)內(nèi)都是平整的,可以直接訪(fǎng)問(wèn)
- 使用便利,協(xié)議文件設(shè)計(jì)好后可以發(fā)布,可以隨時(shí)往Table里面添加或者刪除成員
1.2.2 缺點(diǎn):
- 效率高的同時(shí)導(dǎo)致cpu資源占用相對(duì)較高
- 傳輸?shù)臄?shù)據(jù)可能比對(duì)數(shù)據(jù)進(jìn)行壓縮后再傳輸要大
- 打包后的FlatBuffers中的矢量數(shù)據(jù)不能隨意修改(一般打包后直接發(fā)送,沒(méi)有這個(gè)需求)
- FlatBuffers傳輸?shù)臄?shù)據(jù)沒(méi)有JSON、XML和HTML那么直觀
1.2.3 數(shù)據(jù)結(jié)構(gòu)
- struct
Struct 標(biāo)量,修改時(shí)需要全量編譯;優(yōu)點(diǎn)是訪(fǎng)問(wèn)速度快,占用內(nèi)存少。 - Table
Table 矢量,可以增刪,刪除時(shí)定義為deprecated(向后兼容) - root_type
是一個(gè)頂級(jí)類(lèi)型。 - union
聯(lián)合
標(biāo)量都是直接寫(xiě)到緩沖區(qū)去的,所有的矢量需要先寫(xiě)到緩沖區(qū),然后獲得偏移量(32位),然后再把偏移量寫(xiě)到適當(dāng)?shù)慕Y(jié)構(gòu)中,每個(gè)矢量都離不開(kāi)一個(gè)偏移量。
1.2.4 數(shù)據(jù)類(lèi)型
- 標(biāo)量
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)
括號(hào)內(nèi)的名字是它前面類(lèi)型的別名,兩者使用方式等價(jià)。 - 矢量類(lèi)型包括:
向量,使用[type]形式
string,僅支持UTF-8或者7位ASCII碼,其他編碼或者通常的二進(jìn)制數(shù)據(jù)可以使用向量[byte]/[ubyte]替代
引用其他tables/structs/enums/unions
1.2.5 使用步驟
- 編寫(xiě) schema 文件,描述數(shù)據(jù)結(jié)構(gòu)和接口定義。
- 用 flatc 編譯,生成相應(yīng)語(yǔ)言的代碼文件。
- 使用 FlatBuffers 支持的語(yǔ)言(如C ++,Java等)生成的文件進(jìn)行開(kāi)發(fā)。
1.2.6 橫向?qū)Ρ?/h3>
非扁平化(多層鍵值對(duì)結(jié)構(gòu))數(shù)據(jù)和等效的扁平化(多維數(shù)組)數(shù)據(jù)* 數(shù)據(jù)量小、快速迭代、包含大量字符串數(shù)據(jù),使用JSON,方便快捷;
- 數(shù)據(jù)量小、接口穩(wěn)定、靜態(tài)語(yǔ)言主導(dǎo)、多語(yǔ)言協(xié)作、集成IDL、依賴(lài)gPRC,考慮 protocol buffers。
- 數(shù)據(jù)量大、接口穩(wěn)定、靜態(tài)語(yǔ)言主導(dǎo)、集成IDL、數(shù)據(jù)無(wú)法扁平化,考慮 flat buffers。
- 數(shù)據(jù)量大、快速迭代、性能要求高、數(shù)據(jù)可以扁平化,不希望使用重量級(jí)工具或修改工程結(jié)構(gòu),考慮DIMBIN。
二 Android 使用 FlatBuffers
- 準(zhǔn)備 flatc 的編譯工具
- 導(dǎo)入 flatbuffers java庫(kù)
- FlatBufferBuilder 的使用
2.1 準(zhǔn)備 flatc 的編譯工具
非扁平化(多層鍵值對(duì)結(jié)構(gòu))數(shù)據(jù)和等效的扁平化(多維數(shù)組)數(shù)據(jù)* 數(shù)據(jù)量小、快速迭代、包含大量字符串數(shù)據(jù),使用JSON,方便快捷;
- 準(zhǔn)備 flatc 的編譯工具
- 導(dǎo)入 flatbuffers java庫(kù)
- FlatBufferBuilder 的使用
下載編譯 FlatBuffers
- 使用 homebrew 進(jìn)行下載:
brew install flatBuffer - 或者下載源碼進(jìn)行編譯:
https://github.com/google/flatbuffers/releases
$ cd flatbuffers-1.12.0
$ cmake .
$ make
$ make install
$ flatc --version
2.3 導(dǎo)入 flatbuffers java庫(kù)
- Maven 導(dǎo)入
implementation 'com.google.flatbuffers:flatbuffers-java:1.12.0' - 或者源碼導(dǎo)入為模塊
https://github.com/google/flatbuffers/tree/master/java/com/google/flatbuffers
然后進(jìn)行依賴(lài)implementation project(path: ':flatbuffers')
2.4 FlatBufferBuilder 的簡(jiǎn)單使用
Kotlin main
-
創(chuàng)建 .fbs
image.png 測(cè)試代碼
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
}
}
最后
基于效率和性能問(wèn)題,項(xiàng)目慢慢使用 FlatBuffers:
- 跨平臺(tái)/語(yǔ)言開(kāi)發(fā)
- JSON解析的效率和內(nèi)存問(wèn)題
