flatbuffer介紹和用法


介紹

flatbuffer是google發布的一個跨平台序列化框架具有如下特點

1、對序列化的數據不需要打包和拆包

2、內存和效率速度高,擴展靈活

3、代碼依賴較少

4、強類型設計,編譯期即可完成類型檢查

5、使用簡單、可跨平台使用

安裝

git clone git@github.com:google/flatbuffers.git
cd flatbuffers
brew install cmake
cmake -G "Unix Makefiles"
make
make install
flatc --version

編寫flatbuffer文件

// Example IDL file for our monster's schema.
namespace com.frank.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;

將文件保存為monster.fbs,下面進行編譯

flatc --java monster.fbs

執行完后會在當前目錄下生成Java文件

IntelliJ測試flatbuffer

將生成的Java代碼拷到項目中,新建SampleBinary類

package com.frank.learning;

import com.google.flatbuffers.FlatBufferBuilder;

import java.nio.ByteBuffer;

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);
        }
    }
}

pom文件加入flatbuffer相關jar包

<dependency>
    <groupId>com.google.flatbuffers</groupId>
    <artifactId>flatbuffers-java</artifactId>
    <version>1.12.0</version>
</dependency>

輸出結果如下

300
150
Orc
X: 1.0  Y: 2.0  Z: 3.0
13
weaponsLength: 2  secondWeaponName: Axe  secondWeaponDamage: 5
weaponName: Axe  weaponDamage: 5

flatbuffer原理

flatbuffer將數據存在一個一維數組當中,緩存在一個bytebuffer當中。一個flatbuffer對象在數組中被分為兩部分,元數據部分和數據部分。元數據負責存放相對於中間部分的索引,數據部分存放真實的value。分割的節點為(pivot point)。它的將數據以及對應的數據位置都保存在一個線性的數組中。使用的時候只需要把byte流發送出去,解析的時候只需要根據保存的位置,截取對應的數值即可。

例子:
假設我們創建了一個Person對象,它的name是John,friendshipStatus是2.那么對應圖中元數據部分第一個byte是1--->從中心點處數一個位置,開始的字符就是name的值即john。第二個byte是6,從中心點數6個位置值是2.
class Person {
    String name;//john
    int friendshipStatus;//2
    Person spouse;
    List<Person>friends;
}

 

 從圖中可以看出來,flatbuffer將索引和數據文件存在一個一位數組中通過查找,還原對象,所以不需要打包和拆包的過程相對高效。

參考學習鏈接

1、https://www.jianshu.com/p/8df23cd182ec

2、https://www.jianshu.com/p/fa999434776a

3、https://google.github.io/flatbuffers/flatbuffers_guide_tutorial.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM