最近有項目用到了FlatBuffer净嘀,本文就以極簡的方式介紹FlatBuffers的環(huán)境配置和使用方式奏寨。
作者使用MAC OSX操作系統(tǒng)抖部,使用IDEA開發(fā)工具《В可能讀者環(huán)境與作者有所不同践惑,但無論是什么環(huán)境,整體思路和步驟是相似的嘶卧,希望本文能給讀者有所幫助尔觉。
一、FlatBuffers簡介
FlatBuffers為Google發(fā)布的一個跨平臺芥吟,提供多種語言接口穷娱,注重性能和資源使用的序列化類庫绑蔫。目前該類庫提供C++, C#, C, Go, Java, JavaScript, PHP, and Python語言接口。該序列化類庫多用于移動端手游數(shù)據(jù)傳輸以及特定的對性能有較高要求的應用泵额。
接下來我們將學習FlatBuffers環(huán)境搭建并且使用Java語言完成一次簡單的序列化例子配深。
- 編譯
flatc
工具 - 編寫一個FlatBuffers的scheme文件
- 使用
flatc
工具編譯scheme文件,生成對應語言的數(shù)據(jù)對象頭文件/類 - 使用FlatBufferBuilder序列化對象
- 反序列化數(shù)據(jù)對象
二嫁盲、編譯flatc工具
FlatBuffers源碼工程在CMake/文件夾下為我們提供了*.cmake文件篓叶,方便我們使用Cmake工具編譯工程生成flatc
工具。
2.1 Cmake環(huán)境配置
Cmake官網(wǎng)下載制定平臺的二進制安裝包羞秤,筆者為MAC OSX平臺所以直接下載dmg格式的安裝文件缸托,讀者可根據(jù)自身平臺下載相應的二進制安裝包。當然讀者也可以直接下載具體平臺的源碼進行編譯瘾蛋。
下載安裝完成后需要將cmake
命令加入PATH下俐镐,筆者使用zsh的shell,因此相關(guān)的配置文件在~/.zshrc文件下,如果讀者使用不同shell,請在正確的位置配置哺哼。
export CMAKE_HOME=/Applications/CMake.app/Contents
export PATH=$CMAKE_HOME/bin:$PATH
其中/Applications/CMake.app/Contents
為Cmake的安裝根目錄佩抹,讀者需根據(jù)具體安裝位置進行修改。
然后運行如下命令將最新加載最新配置:
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/目錄下(環(huán)境配置不同可能有所不同)栏豺,重新啟動終端輸入
flatc --version
命令會打印當前flatc的版本信息,筆者輸出結(jié)果如下:
flatc version 1.6.0
至此豆胸,我們完成了flatc工具的編譯和安裝冰悠。
三、編寫FlatBuffers的scheme文件
本文使用官網(wǎng)教程里面的例子配乱,筆者進行了整理并加入自己的理解和說明溉卓。
// 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環(huán)境下為包名桑寨。然后使用enum關(guān)鍵字定義類枚舉類型Color,使用union定義共用體(C風格),struct定義了名為Vec3的結(jié)構(gòu)體忿檩,table定義了名為Monster復合類結(jié)構(gòu)尉尾,其中它包含定義的結(jié)構(gòu)體、共用體燥透、枚舉等沙咏。最后root_type指明Monster類為根類型辨图。當然這里我們只是很簡單的講解了scheme的含義,如果想具體了解語法知識可查看寫一個scheme這篇官網(wǎng)文檔肢藐。
四故河、編譯scheme文件
將上節(jié)編寫的scheme文件保存為monster.fbs文件,到該文件所在文件夾下吆豹,執(zhí)行
flatc --java monster.fbs
將會生成Java語言的類文件定義鱼的,如果你想為別的語言生成相應的類文件可查看該文檔。
五痘煤、代碼示例
創(chuàng)建一個普通的java工程凑阶,你有兩種方式引入FlatBuffers的相關(guān)語言的API:
- 將FlatBuffers源碼下java文件夾內(nèi)容拷貝到項目工程源碼路徑下;
- 或者 使用Maven或Gradle項目管理工具從Maven倉庫下載Jar包衷快。
筆者使用Gradle創(chuàng)建項目宙橱,因此在項目build.gradle文件內(nèi)依賴關(guān)系配置如下:
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創(chuàng)建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");
// 創(chuàng)建一個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聲明開始創(chuàng)建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);
// 調(diào)用finish方法完成Monster對象
builder.finish(orc); // You could also call `Monster.finishMonsterBuffer(builder, orc);`.
// 生成二進制文件
byte[] buf = builder.sizedByteArray();
// 至此完成對象數(shù)據(jù)序列化
//模擬從獲取到二進制數(shù)據(jù) 進行反序列化對象
ByteBuffer buffer = ByteBuffer.wrap(buf);
//根據(jù)該二進制數(shù)據(jù)列生成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完成對象序列化然后將序列化的二進制數(shù)據(jù)反序列化并打印出來。代碼中對關(guān)鍵部分都增加了代碼注釋都伪,這里就不再詳細解釋帶嗎細節(jié)了。
至此我們完成了FlatBuffers工具的入門积担,讀者可以直接下載示例代碼以便加深理解陨晶。