FlatBuffers入门简介

最近有项目用到了FlatBuffer,本文就以极简的方式介绍FlatBuffers的环境配置和使用方式。
作者使用MAC OSX操作系统,使用IDEA开发工具。可能读者环境与作者有所不同,但无论是什么环境,整体思路和步骤是相似的,希望本文能给读者有所帮助。

一、FlatBuffers简介

FlatBuffers为Google发布的一个跨平台,提供多种语言接口,注重性能和资源使用的序列化类库。目前该类库提供C++, C#, C, Go, Java, JavaScript, PHP, and Python语言接口。该序列化类库多用于移动端手游数据传输以及特定的对性能有较高要求的应用。
接下来我们将学习FlatBuffers环境搭建并且使用Java语言完成一次简单的序列化例子。

  • 编译flatc工具
  • 编写一个FlatBuffers的scheme文件
  • 使用flatc工具编译scheme文件,生成对应语言的数据对象头文件/类
  • 使用FlatBufferBuilder序列化对象
  • 反序列化数据对象

二、编译flatc工具

FlatBuffers源码工程在CMake/文件夹下为我们提供了*.cmake文件,方便我们使用Cmake工具编译工程生成flatc工具。

2.1 Cmake环境配置

Cmake官网下载制定平台的二进制安装包,笔者为MAC OSX平台所以直接下载dmg格式的安装文件,读者可根据自身平台下载相应的二进制安装包。当然读者也可以直接下载具体平台的源码进行编译。
下载安装完成后需要将cmake命令加入PATH下,笔者使用zsh的shell,因此相关的配置文件在~/.zshrc文件下,如果读者使用不同shell,请在正确的位置配置。

 export CMAKE_HOME=/Applications/CMake.app/Contents
 export PATH=$CMAKE_HOME/bin:$PATH

其中/Applications/CMake.app/Contents为Cmake的安装根目录,读者需根据具体安装位置进行修改。
然后运行如下命令将最新加载最新配置:

source .zshrc

重新启动终端输入如下命令

cmake --help

若看到如下信息则证明配置完成:

Usage

  cmake [options] <path-to-source>
  cmake [options] <path-to-existing-build>

......//省略更多的信息

2.2 下载FlatBuffers源码

从gitHub上下载项目源代码:

git clone git@github.com:google/flatbuffers.git

2.3 编译、安装flatc

进入flatbuffers项目根目录,输入如下命令:

cmake -G "Unix Makefiles"

稍等一会cmake就完成了MakeFile的生成,接下来运行:

make

开始编译,稍等一会编译成功后会在根目录下生成flatc工具。
接下来我们使用

make install

命令,安装flatc,该命令将flatc工具拷贝到/usr/local/bin/目录下(环境配置不同可能有所不同),重新启动终端输入

flatc --version

命令会打印当前flatc的版本信息,笔者输出结果如下:

flatc version 1.6.0

至此,我们完成了flatc工具的编译和安装。

三、编写FlatBuffers的scheme文件

本文使用官网教程里面的例子,笔者进行了整理并加入自己的理解和说明。

// Example IDL file for our monster's schema.
namespace com.zeyuan.learning;
enum Color:byte { Red = 0, Green, Blue = 2 }
union Equipment { Weapon } // Optionally add more tables.
struct Vec3 {
  x:float;
  y:float;
  z:float;
}
table Monster {
  pos:Vec3; // Struct.
  mana:short = 150;
  hp:short = 100;
  name:string;
  friendly:bool = false (deprecated);
  inventory:[ubyte];  // Vector of scalars.
  color:Color = Blue; // Enum.
  weapons:[Weapon];   // Vector of tables.
  equipped:Equipment; // Union.
}
table Weapon {
  name:string;
  damage:short;
}
root_type Monster;

我们对上述文件进行简要说明。整个文件配置方式偏向类C的方式第一行namespace定义了该scheme的命名空间,在JAVA环境下为包名。然后使用enum关键字定义类枚举类型Color,使用union定义共用体(C风格),struct定义了名为Vec3的结构体,table定义了名为Monster复合类结构,其中它包含定义的结构体、共用体、枚举等。最后root_type指明Monster类为根类型。当然这里我们只是很简单的讲解了scheme的含义,如果想具体了解语法知识可查看写一个scheme这篇官网文档。

四、编译scheme文件

将上节编写的scheme文件保存为monster.fbs文件,到该文件所在文件夹下,执行

flatc --java monster.fbs

将会生成Java语言的类文件定义,如果你想为别的语言生成相应的类文件可查看该文档

五、代码示例

创建一个普通的java工程,你有两种方式引入FlatBuffers的相关语言的API:

  • 将FlatBuffers源码下java文件夹内容拷贝到项目工程源码路径下;
  • 或者 使用Maven或Gradle项目管理工具从Maven仓库下载Jar包。

笔者使用Gradle创建项目,因此在项目build.gradle文件内依赖关系配置如下:

dependencies {
    testCompile group: 'junit', name: 'junit', version: '4.12'
    // https://mvnrepository.com/artifact/com.github.davidmoten/flatbuffers-java
    compile 'com.github.davidmoten:flatbuffers-java:1.6.0.2'
}

工程测试代码如下:

public class SampleBinary {

    public static void  main(String[] args){

        //使用FlatBufferBuilder 完成对象序列化
        FlatBufferBuilder builder = new FlatBufferBuilder(1024);

        //返回该String的偏移地址
        int weaponOneName = builder.createString("Sword");
        short weaponOneDamage = 3;
        int weaponTwoName = builder.createString("Axe");
        short weaponTwoDamage = 5;

        // 使用createWeapon创建Weapon对象,并返回该对象的偏移地址
        int sword = Weapon.createWeapon(builder, weaponOneName, weaponOneDamage);
        int axe = Weapon.createWeapon(builder, weaponTwoName, weaponTwoDamage);

        // Serialize a name for our monster, called "Orc".
        int name = builder.createString("Orc");

        // 创建一个Vector对象,并且返回它的偏移地址
        byte[] treasure = {0, 1, 13, 12, 4, 5, 6, 7, 8, 9};
        int inv = Monster.createInventoryVector(builder, treasure);

        // Place the two weapons into an array, and pass it to the `createWeaponsVector()` method to
        // create a FlatBuffer vector.
        int[] weaps = new int[2];
        weaps[0] = sword;
        weaps[1] = axe;
        // Pass the `weaps` array into the `createWeaponsVector()` method to create a FlatBuffer vector.
        int weapons = Monster.createWeaponsVector(builder, weaps);

        // startMonster声明开始创建Monster对象,使用endMonster声明完成Monster对象
        Monster.startMonster(builder);
        Monster.addPos(builder, Vec3.createVec3(builder, 1.0f, 2.0f, 3.0f));
        Monster.addName(builder, name);
        Monster.addColor(builder, Color.Red);
        Monster.addHp(builder, (short)300);
        Monster.addInventory(builder, inv);
        Monster.addWeapons(builder, weapons);
        Monster.addEquippedType(builder, Equipment.Weapon);
        Monster.addEquipped(builder, axe);
        int orc = Monster.endMonster(builder);

        // 调用finish方法完成Monster对象
        builder.finish(orc); // You could also call `Monster.finishMonsterBuffer(builder, orc);`.

        // 生成二进制文件
        byte[] buf = builder.sizedByteArray();

        // 至此完成对象数据序列化


        //模拟从获取到二进制数据 进行反序列化对象
        ByteBuffer buffer = ByteBuffer.wrap(buf);

        //根据该二进制数据列生成Monster对象
        Monster monster = Monster.getRootAsMonster(buffer);

        short hp = monster.hp();
        System.out.println(hp);

        short mana = monster.mana();
        System.out.println(mana);
        String resultName = monster.name();
        System.out.println(resultName);

        Vec3 pos = monster.pos();
        float x = pos.x();
        float y = pos.y();
        float z = pos.z();
        System.out.println("X: "+x+"  Y: "+y+"  Z: "+z);

        int invLength = monster.inventoryLength();
        int thirdItem = monster.inventory(2);
        System.out.println(thirdItem);

        int weaponsLength = monster.weaponsLength();
        String secondWeaponName = monster.weapons(1).name();
        short secondWeaponDamage = monster.weapons(1).damage();
        System.out.println("weaponsLength: "+weaponsLength+"  secondWeaponName: "+secondWeaponName+"  secondWeaponDamage: "+secondWeaponDamage);
        int unionType = monster.equippedType();
        if (unionType == Equipment.Weapon) {
            Weapon weapon = (Weapon)monster.equipped(new Weapon()); // Requires explicit cast
            // to `Weapon`.
            String weaponName = weapon.name();    // "Axe"
            short weaponDamage = weapon.damage(); // 5
            System.out.println("weaponName: "+weaponName+"  weaponDamage: "+weaponDamage);
        }
    }
}

上述代码主要是使用FlatBufferBuilder完成对象序列化然后将序列化的二进制数据反序列化并打印出来。代码中对关键部分都增加了代码注释,这里就不再详细解释带吗细节了。

至此我们完成了FlatBuffers工具的入门,读者可以直接下载示例代码以便加深理解。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,602评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,442评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,878评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,306评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,330评论 5 373
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,071评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,382评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,006评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,512评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,965评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,094评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,732评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,283评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,286评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,512评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,536评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,828评论 2 345

推荐阅读更多精彩内容