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閱讀 229,237評論 6 537
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,957評論 3 423
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 177,248評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,356評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,081評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,485評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,534評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,720評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,263評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,025評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,204評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,787評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,461評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,874評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,105評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,945評論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,205評論 2 375

推薦閱讀更多精彩內容