flatdir android什么作用,FlatBuffers在android的使用简介

mac环境上编辑器flatc生成

下载flatbuffers的源码,解压

homebrew下载安装cmake

cd到flatbuffers的源码文件夹

开始编译flatc

cd flatbuffers/

cmake -G "Unix Makefiles"

make

指定生成的对象为Unix makefile,以便cmake根据CMakeLists.txt文件生成对应的makefile文件。(在当前目录下可以看到生成的makefile文件,直接执行make命令即可得到flatc。

Java文件编译

./flatc -j -o ~/workspace/testfb repos_schema.fbs

-j表示生成java文件,–o 表示将文件编译到指定目录~/workspace/testfb下,schema文件的位置放在命令的最后。

命令详细用法可见官方文档

schema语法

源码剖析

重点:扁平二进制的存储方式。

使用bytebuffer操作byte数据

逆向存储,将数据概要信息放在整个buffer的头部。这也回答了作者文中的疑问,为什么要费劲的反向存储,即从buffer的尾部开始写数据。

offset的概念,每个数据距离buffer尾部的长度。

vtable中存储的是某个数据相对于vtable的偏移。寻址时只要将当前pos+偏移就得到真实数据信息摘要所在位置。因此,根据roottype的数据Vtable,就可以找到一切。

androidstudio中的使用示例

gradle添加依赖

compile 'com.github.davidmoten:flatbuffers-java:1.4.0.1'

定义schema

我们以这个数据样式(Json)为例

{

"error_no":0,

"message":"",

"result":{

"data":[

{

"datatype":1,

"itemdata":

{//共有字段45个

"sname":"\u5fae\u533b",

"packageid":"330611",

"tabs":[

{

"type":1,

"f":"abc"

},

]

}

},

],

"hasNextPage":true,

"dirtag":"soft"

}

}

编写schema如下

namespace flats;

table TabFB {

type : int;

f : string;

}

table ItemDataFB {

sname : string;

packageid : string;

...

tabs : [TabFB];

}

table DataFB {

datatype : int;

itemdata : ItemDataFB;

}

table ResultFB {

data : [DataFB];

hasNextPage : bool;

dirtag : string;

}

table ResponseFB {

error_no : int;

message : string;

result : ResultFB;

}

root_type ResponseFB;

就以上示例简单讲解一下:

命名空间

namespace决定了编译生成文件的存放位置,类似c的写法,同样,不同的schema文件可以互相引用,通过include的方式

table-表

表是在FlatBuffers中定义对象的主要方式,它由一个名称和一个字段列表组成。每个字段都有一个名称,一个类型和可选的默认值(如果省略,则默认为0/ NULL)。

每个字段都是可选的,因此,可以灵活地添加字段,而不必担心数据膨胀。此设计也是FlatBuffer的前后兼容机制。

注意:

只能在表定义的末尾添加新字段。较旧的数据仍将正确读取,并在读取时给予默认值。

不能从模式中删除不再使用的字段,可以用deprecated标记它们,这将阻止在生成class中生成访问器,以此来强制不再使用该字段。

根类型

root_type必须指定,序列化数据的根结构,解析开始的位置。

flatc编译后生成文件目录如下

03a2e8918f8a

编译生成文件目录.png

将编译生成的文件导入工程即可开始编码了。

序列化示例

public static void writeResponseToFbFile(String fbfilepath, ResponseJson responseJson) {

FlatBufferBuilder builder = new FlatBufferBuilder(0);

int dataitemsize = responseJson.result.data.size();

int[] dataArr = new int[dataitemsize];

//data begin,每个Data下有多个itemdata

for (int i = 0; i < dataitemsize; i++) {

DataItemJson dataItemJson = responseJson.result.data.get(i);

ItemJson itemJson = dataItemJson.itemdata;

//itemdata begin

int sname = builder.createString(itemJson.sname);

int packageid = builder.createString(itemJson.packageid);

....

//tabs begin,多个tab

int tabnum = itemJson.tabs.size();

int[] tabsArr = new int[tabnum];

for (int j = 0; j < tabnum; j ++) {

//TabFB begin

TabsJson tabsJson = itemJson.tabs.get(j);

tabsArr[j] = TabFB.createTabFB(builder, tabsJson.type, builder.createString(tabsJson.f));

//TabFB end

}

int tabs = ItemDataFB.createTabsVector(builder,tabsArr);

//tabs end,返回tabs vtable所在位置的offset

ItemDataFB.startItemDataFB(builder);

ItemDataFB.addSname(builder,sname);

ItemDataFB.addPackageid(builder, packageid);

ItemDataFB.addTabs(builder,tabs);

int itemdataofset = ItemDataFB.endItemDataFB(builder);

//ItemDataFB end,返回itemdata的offset

//DataFb

int dataoffset = DataFB.createDataFB(builder, dataItemJson.datatype, itemdataofset);

//将当前data数据的offset写入vtable

dataArr[i] = dataoffset;

}

//封装result

int data = ResultFB.createDataVector(builder,dataArr);

int dirtag = builder.createString(responseJson.result.dirtag);

int resultOfset = ResultFB.createResultFB(builder,data,responseJson.result.hasNextPage,dirtag);

// response

int message = builder.createString(responseJson.message);

int responseOfset = ResponseFB.createResponseFB(builder,responseJson.error_no,message,resultOfset);

//调用finish结束此次构造

builder.finish(responseOfset);

}

序列化后的数据写入文件,特容易踩坑!

ByteBuffer bb = builder.dataBuffer();

File file = new File(fbfilepath);

try {

FileOutputStream fo = new FileOutputStream(file);

fo.write(bb.array(),bb.position(),bb.remaining());

fo.close();

} catch (FileNotFoundException e) {

e.printStackTrace();

} catch (IOException e) {

e.printStackTrace();

}

这里要特别注意,由于flatbuffers的数据写入方向是反向写入!!因此build结束时数据的开始位置为position标记所在位置,因此要指定write的开始为bb.position(),写入长度为bb.remaining(),否则会导致文件反序列化失败。

反序列化

public static void parse (byte[] bytes) {

ByteBuffer bb = ByteBuffer.wrap(bytes);

ResponseFB responsefb = ResponseFB.getRootAsResponseFB(bb);

int errorno = responsefb.errorNo();

responsefb.message();

ResultFB resultFB = responsefb.result();

resultFB.hasNextPage();

resultFB.dirtag();

int len = resultFB.dataLength();

for (int i = 0; i < len; i++) {

resultFB.data(i).datatype();

ItemDataFB item = resultFB.data(i).itemdata();

String s = item.sname();

item.packageid();

...

int tabslen = item.tabsLength();

for (int j = 0; j < tabslen; j++) {

TabFB tab = item.tabs(j);

tab.f();

tab.type();

}

}

}

这里需要说明的是,序列化过程中每个table中的数据可以无序写入,而反序列化时也不必按序读出,因为扁平二进制的存储方式已经保证了读取方式寻址进行而不会出错。此外,反序列化的速度直接受读取数据多少的影响,由于反序列化不需要进行封包解析的过程,因此数据可以随意读取,而读取的数据个数越多所消耗的时间越长。这也是flatbuffers的妙处所在。

flatbuffers还有很多更有趣的用法等待探索。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值