https://github.com/google/flatbuffers到这里下载文件。
要开始使用flatbuffe,你要先写一个schema文件。详细写法点这里。
// Example IDL file for our monster's schema.
namespace MyGame.Sample;
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;
在你写好FlatBuffers schema之后,你要使用工具去生成对应语言所需的代码。
工具在build目录下。使用vs或xcode编译就可以了。
这里以c#为例,对应的命令为:
cd flatbuffers/sample
./../flatc --csharp samples/monster.fbs。
我们已经为我们所需的语言编译了schema,我们可以开始创建monster了,并且可通过FlatBuffers以序列化和反序列化他们。
引入命名空间:
using FlatBuffers;
using MyGame.Sample; // The `flatc` generated files. (Monster, Vec3, etc.)
创建一个FlatBufferBuilder的实例,这个实例将包含缓存。
// Create a `FlatBufferBuilder`, which will be used to create our
// monsters' FlatBuffers.
var builder = new FlatBufferBuilder(1);
var weaponOneName = builder.CreateString("Sword");
var weaponOneDamage = 3;
var weaponTwoName = builder.CreateString("Axe");
var weaponTwoDamage = 5;
// Use the `CreateWeapon()` helper function to create the weapons, since we set every field.
var sword = Weapon.CreateWeapon(builder, weaponOneName, (short)weaponOneDamage);
var axe = Weapon.CreateWeapon(builder, weaponTwoName, (short)weaponTwoDamage);
下面我们来创建我们的Monster,一个兽人。他的属性是:红色(表示愤怒),300的HP,坐标(1.0,2.0,3.0),几把可选武器(这里就用我们之前创建的剑和斧子)。然后给他装备上攻击力较高的斧子。还有我们再给他一些在被击败时可能掉落的物品。
在我们序列化monster之前。我们要先序列化他里面的对象。我们这里先序列化名字和掉落物品。
// Serialize a name for our monster, called "Orc".
var name = builder.CreateString("Orc");
// 创建一个矢量来表示会掉落的物品,
// 每一个数字都可以和一个道具通信。在兽人死后,对应的道具就会被声明。
//注意:我们放入byte的顺序,和取出来的时候是反的(比如我先放入的是9,但是数组里第9个才是9)
Monster.StartInventoryVector(builder, 10);
for (int i = 9; i >= 0; i--)
{
builder.AddByte((byte)i);
}
var inv = builder.EndVector();
如果我们要创建一个嵌套的对象(比如table,string,或者其它矢量)的矢量,先把他们的offset放到一个临时的数据结构里,然后创建一个包含这里矢量的额外的矢量。
看下这个例子:
var weaps = new Offset[2];
weaps[0] = sword;
weaps[1] = axe;
// Pass the `weaps` array into the `CreateWeaponsVector()` method to create a FlatBuffer vector.
var weapons = Monster.CreateWeaponsVector(builder, weaps);
// Create a `Vec3`, representing the Orc's position in 3-D space.
var pos = Vec3.CreateVec3(builder, 1.0f, 2.0f, 3.0f);
// Create our monster using `StartMonster()` and `EndMonster()`.
Monster.StartMonster(builder);
Monster.AddPos(builder, pos);
Monster.AddHp(builder, (short)300);
Monster.AddName(builder, name);
Monster.AddInventory(builder, inv);
Monster.AddColor(builder, Color.Red);
Monster.AddWeapons(builder, weapons);
Monster.AddEquippedType(builder, Equipment.Weapon);
Monster.AddEquipped(builder, axe.Value); // Union类型包含两个字段。
var orc = Monster.EndMonster(builder);
buffer已经建好。下面来完成它:
// Call `Finish()` to instruct the builder that this monster is complete.
builder.Finish(orc.Value); // You could also call `Monster.FinishMonsterBuffer(builder, orc);`.
下面我写一个存储的例子:
using (var ms = new MemoryStream(builder.DataBuffer.Data, builder.DataBuffer.Position, builder.Offset))
{
var data = ms.ToArray();
File.WriteAllBytes(@"Resources/monsterdata_cstest.mon",data);
}
using FlatBuffers;
using MyGame.Sample; // The `flatc` generated files. (Monster, Vec3, etc.)
读文件(这里是从硬盘读取,你也可以从网络等途径)
var data = File.ReadAllBytes(@"Resources/monsterdata_test.mon");
var bb = new ByteBuffer(data);
var monster = Monster.GetRootAsMonster(bb);
// For C#, unlike other languages support by FlatBuffers, most values (except for
// vectors and unions) are available as propreties instead of asccessor methods.
var hp = monster.Hp
var mana = monster.Mana
var name = monster.Name
var pos = monster.Pos
var x = pos.X
var y = pos.Y
var z = pos.Z
int invLength = monster.InventoryLength;
var thirdItem = monster.GetInventory(2);
int weaponsLength = monster.WeaponsLength;
var secondWeaponName = monster.GetWeapons(1).Name;
var secondWeaponDamage = monster.GetWeapons(1).Damage;
var unionType = monster.EquippedType;
if (unionType == Equipment.Weapon) {
var weapon = (Weapon)monster.GetEquipped(new Weapon()); // Requires explicit cast
// to `Weapon`.
var weaponName = weapon.Name; // "Axe"
var weaponDamage = weapon.Damage; // 5
}
如果你在调用flac的时候使用了--gen-mutable,你就可以修改了。
var monster = Monster.GetRootAsMonster(buf);
monster.MutateHp(10); // Set table field.
monster.Pos.MutateZ(4); // Set struct field.
monster.MutateInventory(0, 1); // Set vector element.
Mutate方法会返回一个bool值来告诉你是否修改成功。
注意:如果你在创建的时候没有写入某个字段的值,或者写入的值和默认值是相等的。那么这个值其实是没有被储存的,而是储存在代码内,所以无法修改这个值,mutate方法也会返回false。如果你希望默认值也被储存到buffer里,那你需要调用ForceDefaults 方法。c#中没有这个方法!