File: README.md
FlatBuffers
FlatBuffers is a cross platform serialization library architected for
maximum memory efficiency. It allows you to directly access serialized data without parsing/unpacking it first, while still having great forwards/backwards compatibility.
Quick Start
Build the compiler for flatbuffers (
flatc)Use
cmaketo create the build files for your platform and then perform the compilation (Linux example).textcmake -G "Unix Makefiles" make -jDefine your flatbuffer schema (
.fbs)Write the schema to define the data you want to serialize. See monster.fbs for an example.
Generate code for your language(s)
Use the
flatccompiler to take your schema and generate language-specific code:text./flatc --cpp --rust monster.fbsWhich generates
monster_generated.handmonster_generated.rsfiles.Serialize data
Use the generated code, as well as the
FlatBufferBuilderto construct your serialized buffer. (C++example)Transmit/store/save Buffer
Use your serialized buffer however you want. Send it to someone, save it for later, etc...
Read the data
Use the generated accessors to read the data from the serialized buffer.
It doesn't need to be the same language/schema version, FlatBuffers ensures the data is readable across languages and schema versions. See the
Rustexample reading the data written byC++.
Documentation
Go to our landing page to browse our documentation.
Supported operating systems
- Windows
- macOS
- Linux
- Android
- And any others with a recent C++ compiler (C++ 11 and newer)
Supported programming languages
Code generation and runtime libraries for many popular languages.
- C
- C++ - snapcraft.io
- C# - nuget.org
- Dart - pub.dev
- Go - go.dev
- Java - Maven
- JavaScript - NPM
- Kotlin
- Lobster
- Lua
- PHP
- Python - PyPI
- Rust - crates.io
- Swift - swiftpackageindex
- TypeScript - NPM
- Nim
Versioning
FlatBuffers does not follow traditional SemVer versioning (see rationale) but rather uses a format of the date of the release.
Contribution
- FlatBuffers Issues Tracker to submit an issue.
- stackoverflow.com with
flatbufferstag for any questions regarding FlatBuffers.
To contribute to this project, see CONTRIBUTING.
Community
Security
Please see our Security Policy for reporting vulnerabilities.
Licensing
Flatbuffers is licensed under the Apache License, Version 2.0. See LICENSE for the full license text.
File: benchmarks/swift/README.md
Benchmarks
To open the benchmarks in xcode use:
open --env BENCHMARK_DISABLE_JEMALLOC=true Package.swift
or running them directly within terminal using:
swift package benchmark
File: dart/README.md
FlatBuffers for Dart
This package is used to read and write FlatBuffers.
Most consumers will want to use the flatc - FlatBuffer compiler binary for your platform.
You can download the flatc version matching your dart package version from GitHub releases.
The FlatBuffer compiler flatc reads a FlatBuffers IDL schema and generates Dart code.
The generated classes can be used to read or write binary data/files that are interoperable with
other languages and platforms supported by FlatBuffers, as illustrated in the example.dart in the
examples folder.
For more details and documentation, head over to the official site and read the
Tutorial and how to
use FlatBuffers in Dart.
File: docs/source/languages/c.md
Use in C {#flatbuffers_guide_use_c}
The C language binding exists in a separate project named FlatCC.
The flatcc C schema compiler can generate code offline as well as
online via a C library. It can also generate buffer verifiers and fast
JSON parsers, printers.
Great care has been taken to ensure compatibility with the main flatc
project.
General Documention
- Tutorial - select C as language
when scrolling down - FlatCC Guide
- The C Builder Interface
- The Monster Sample in C
- GitHub
Supported Platforms
- Ubuntu (clang / gcc, ninja / gnu make)
- OS-X (clang / gcc, ninja / gnu make)
- Windows MSVC 2010, 2013, 2015
CI builds recent versions of gcc, clang and MSVC on OS-X, Ubuntu, and
Windows, and occasionally older compiler versions. See main project Status.
Other platforms may well work, including Centos, but are not tested
regularly.
The monster sample project was specifically written for C99 in order to
follow the C++ version and for that reason it will not work with MSVC
2010.
Modular Object Creation
In the tutorial we used the call Monster_create_as_root to create the
root buffer object since this is easier in simple use cases. Sometimes
we need more modularity so we can reuse a function to create nested
tables and root tables the same way. For this we need theflatcc_builder_buffer_create_call. It is best to keep flatcc_builder
calls isolated at the top driver level, so we get:
ns(Monster_ref_t) create_orc(flatcc_builder_t *B)
{
// ... same as in the tutorial.
return s(Monster_create(B, ...));
}
void create_monster_buffer()
{
uint8_t *buf;
size_t size;
flatcc_builder_t builder, *B;
// Initialize the builder object.
B = &builder;
flatcc_builder_init(B);
// Only use `buffer_create` without `create/start/end_as_root`.
flatcc_builder_buffer_create(create_orc(B));
// Allocate and copy buffer to user memory.
buf = flatcc_builder_finalize_buffer(B, &size);
// ... write the buffer to disk or network, or something.
free(buf);
flatcc_builder_clear(B);
}The same principle applies with start/end vs start/end_as_root in
the top-down approach.
Top Down Example
The tutorial uses a bottom up approach. In C it is also possible to use
a top-down approach by starting and ending objects nested within each
other. In the tutorial there is no deep nesting, so the difference is
limited, but it shows the idea:
uint8_t treasure[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
size_t treasure_count = c_vec_len(treasure);
ns(Weapon_ref_t) axe;
// NOTE: if we use end_as_root, we MUST also start as root.
ns(Monster_start_as_root(B));
ns(Monster_pos_create(B, 1.0f, 2.0f, 3.0f));
ns(Monster_hp_add(B, 300));
ns(Monster_mana_add(B, 150));
// We use create_str instead of add because we have no existing string reference.
ns(Monster_name_create_str(B, "Orc"));
// Again we use create because we no existing vector object, only a C-array.
ns(Monster_inventory_create(B, treasure, treasure_count));
ns(Monster_color_add(B, ns(Color_Red)));
if (1) {
ns(Monster_weapons_start(B));
ns(Monster_weapons_push_create(B, flatbuffers_string_create_str(B, "Sword"), 3));
// We reuse the axe object later. Note that we dereference a pointer
// because push always returns a short-term pointer to the stored element.
// We could also have created the axe object first and simply pushed it.
axe = *ns(Monster_weapons_push_create(B, flatbuffers_string_create_str(B, "Axe"), 5));
ns(Monster_weapons_end(B));
} else {
// We can have more control with the table elements added to a vector:
//
ns(Monster_weapons_start(B));
ns(Monster_weapons_push_start(B));
ns(Weapon_name_create_str(B, "Sword"));
ns(Weapon_damage_add(B, 3));
ns(Monster_weapons_push_end(B));
ns(Monster_weapons_push_start(B));
ns(Monster_weapons_push_start(B));
ns(Weapon_name_create_str(B, "Axe"));
ns(Weapon_damage_add(B, 5));
axe = *ns(Monster_weapons_push_end(B));
ns(Monster_weapons_end(B));
}
// Unions can get their type by using a type-specific add/create/start method.
ns(Monster_equipped_Weapon_add(B, axe));
ns(Monster_end_as_root(B));Basic Reflection
The C-API does support reading binary schema (.bfbs)
files via code generated from the reflection.fbs schema, and an
example usage
shows how to use this. The reflection schema files are pre-generated
in the runtime distribution.
Mutations and Reflection
The C-API does not support mutating reflection like C++ does, nor does
the reader interface support mutating scalars (and it is generally
unsafe to do so even after verification).
The generated reader interface supports sorting vectors in-place after
casting them to a mutating type because it is not practical to do so
while building a buffer. This is covered in the builder documentation.
The reflection example makes use of this feature to look up objects by
name.
It is possible to build new buffers using complex objects from existing
buffers as source. This can be very efficient due to direct copy
semantics without endian conversion or temporary stack allocation.
Scalars, structs and strings can be used as source, as well vectors of
these.
It is currently not possible to use an existing table or vector of table
as source, but it would be possible to add support for this at some
point.
Namespaces
The FLATBUFFERS_WRAP_NAMESPACE approach used in the tutorial is convenient
when each function has a very long namespace prefix. But it isn't always
the best approach. If the namespace is absent, or simple and
informative, we might as well use the prefix directly. The
reflection example
mentioned above uses this approach.
Checking for Present Members
Not all languages support testing if a field is present, but in C we can
elaborate the reader section of the tutorial with tests for this. Recall
that mana was set to the default value 150 and therefore shouldn't
be present.
int hp_present = ns(Monster_hp_is_present(monster)); // 1
int mana_present = ns(Monster_mana_is_present(monster)); // 0Alternative ways to add a Union
In the tutorial we used a single call to add a union. Here we show
different ways to accomplish the same thing. The last form is rarely
used, but is the low-level way to do it. It can be used to group small
values together in the table by adding type and data at different
points in time.
ns(Equipment_union_ref_t) equipped = ns(Equipment_as_Weapon(axe));
ns(Monster_equipped_add(B, equipped));
// or alternatively
ns(Monster_equipped_Weapon_add(B, axe);
// or alternatively
ns(Monster_equipped_add_type(B, ns(Equipment_Weapon));
ns(Monster_equipped_add_member(B, axe));Why not integrate with the `flatc` tool?
It was considered how the C code generator could be integrated into theflatc tool, but it
would either require that the standalone C implementation of the schema
compiler was dropped, or it would lead to excessive code duplication, or
a complicated intermediate representation would have to be invented.
Neither of these alternatives are very attractive, and it isn't a big
deal to use the flatcc tool instead of flatc given that the
FlatBuffers C runtime library needs to be made available regardless.
File: docs/source/languages/c_sharp.md
Use in C\# {#flatbuffers_guide_use_c-sharp}
Before you get started
Before diving into the FlatBuffers usage in C#, it should be noted that
the Tutorial page has a complete guide to
general FlatBuffers usage in all of the supported languages (including C#).
This page is designed to cover the nuances of FlatBuffers usage,
specific to C#.
You should also have read the Building
documentation to build flatc and should be familiar with
Using the schema compiler and
Writing a schema.
FlatBuffers C# code location
The code for the FlatBuffers C# library can be found atflatbuffers/net/FlatBuffers. You can browse the library on the
[FlatBuffers GitHub page](https://github.com/google/flatbuffers/tree/master/net/
FlatBuffers).
Building the FlatBuffers C# library
The FlatBuffers.csproj project contains multitargeting for .NET Standard 2.0, 2.1,
.NET 6 and .NET 8.
You can build for a specific framework target when using the cross-platform
.NET Core SDK by adding the -f
command line option:
dotnet build -f netstandard2.1 "FlatBuffers.csproj"The FlatBuffers.csproj project also provides support for defining various
conditional compilation symbols (see "Conditional compilation symbols" section
below) using the -p command line option:
dotnet build -f netstandard2.1 -p:ENABLE_SPAN_T=true -p:UNSAFE_BYTEBUFFER=true "FlatBuffers.csproj"Testing the FlatBuffers C# library
The code to test the libraries can be found at flatbuffers/tests.
The test code for C# is located in the [FlatBuffers.Test](https://github.com/
google/flatbuffers/tree/master/tests/FlatBuffers.Test) subfolder. To run the
tests, open FlatBuffers.Test.csproj in Visual Studio, and compile/run the project.
Optionally, you can run this using Mono instead.
Once you have installed Mono, you can run the tests from the command line
by running the following commands from inside the FlatBuffers.Test folder:
mcs *.cs ../MyGame/Example/*.cs ../../net/FlatBuffers/*.cs
mono Assert.exeUsing the FlatBuffers C# library
Note: See Tutorial for a more in-depth
example of how to use FlatBuffers in C#.
FlatBuffers supports reading and writing binary FlatBuffers in C#.
To use FlatBuffers in your own code, first generate C# classes from your
schema with the --csharp option to flatc.
Then you can include both FlatBuffers and the generated code to read
or write a FlatBuffer.
For example, here is how you would read a FlatBuffer binary file in C#:
First, import the library and generated code. Then, you read a FlatBuffer binary
file into a byte[]. You then turn the byte[] into a ByteBuffer, which you
pass to the GetRootAsMyRootType function:
using MyGame.Example;
using Google.FlatBuffers;
// This snippet ignores exceptions for brevity.
byte[] data = File.ReadAllBytes("monsterdata_test.mon");
ByteBuffer bb = new ByteBuffer(data);
Monster monster = Monster.GetRootAsMonster(bb);Now you can access the data from the Monster monster:
short hp = monster.Hp;
Vec3 pos = monster.Pos;C# code naming follows standard C# style with PascalCasing identifiers,
e.g. GetRootAsMyRootType. Also, values (except vectors and unions) are
available as properties instead of parameterless accessor methods.
The performance-enhancing methods to which you can pass an already created
object are prefixed with Get, e.g.:
// property
var pos = monster.Pos;
// method filling a preconstructed object
var preconstructedPos = new Vec3();
monster.GetPos(preconstructedPos);Storing dictionaries in a FlatBuffer
FlatBuffers doesn't support dictionaries natively, but there is support to
emulate their behavior with vectors and binary search, which means you
can have fast lookups directly from a FlatBuffer without having to unpack
your data into a Dictionary or similar.
To use it:
- Designate one of the fields in a table as the "key" field. You do this
by setting thekeyattribute on this field, e.g.name:string (key).
You may only have one key field, and it must be of string or scalar type. - Write out tables of this type as usual, collect their offsets in an
array. - Instead of calling standard generated method,
e.g.:Monster.createTestarrayoftablesVector,
callCreateSortedVectorOfMonsterin C#
which will first sort all offsets such that the tables they refer to
are sorted by the key field, then serialize it. - Now when you're accessing the FlatBuffer, you can use
theByKeyaccessor to access elements of the vector, e.g.:monster.TestarrayoftablesByKey("Frodo")in C#,
which returns an object of the corresponding table type,
ornullif not found.ByKeyperforms a binary search, so should have a similar
speed toDictionary, though may be faster because of better caching.ByKeyonly works if the vector has been sorted, it will
likely not find elements if it hasn't been sorted.
Buffer verification
As mentioned in C++ Usage buffer
accessor functions do not verify buffer offsets at run-time.
If it is necessary, you can optionally use a buffer verifier before you
access the data. This verifier will check all offsets, all sizes of
fields, and null termination of strings to ensure that when a buffer
is accessed, all reads will end up inside the buffer.
Each root type will have a verification function generated for it,
e.g. Monster.VerifyMonster. This can be called as shown:
var ok = Monster.VerifyMonster(buf);if ok is true, the buffer is safe to read.
For a more detailed control of verification MonsterVerify.Verify
for Monster type can be used:
# Sequence of calls
FlatBuffers.Verifier verifier = new FlatBuffers.Verifier(buf);
var ok = verifier.VerifyBuffer("MONS", false, MonsterVerify.Verify);
# Or single line call
var ok = new FlatBuffers.Verifier(bb).setStringCheck(true).\
VerifyBuffer("MONS", false, MonsterVerify.Verify);if ok is true, the buffer is safe to read.
A second parameter of verifyBuffer specifies whether buffer content is
size prefixed or not. In the example above, the buffer is assumed to not include
size prefix (false).
Verifier supports options that can be set using appropriate fluent methods:
- SetMaxDepth - limit the nesting depth. Default: 1000000
- SetMaxTables - total amount of tables the verifier may encounter. Default: 64
- SetAlignmentCheck - check content alignment. Default: True
- SetStringCheck - check if strings contain termination '0' character. Default: true
Text parsing
There currently is no support for parsing text (Schema's and JSON) directly
from C#, though you could use the C++ parser through native call
interfaces available to each language. Please see the
C++ documentation for more on text parsing.
Object based API
FlatBuffers is all about memory efficiency, which is why its base API is written
around using as little as possible of it. This does make the API clumsier
(requiring pre-order construction of all data, and making mutation harder).
For times when efficiency is less important a more convenient object based API
can be used (through --gen-object-api) that is able to unpack & pack a
FlatBuffer into objects and standard System.Collections.Generic containers,
allowing for convenient construction, access and mutation.
To use:
// Deserialize from buffer into object.
MonsterT monsterobj = GetMonster(flatbuffer).UnPack();
// Update object directly like a C# class instance.
Console.WriteLine(monsterobj.Name);
monsterobj.Name = "Bob"; // Change the name.
// Serialize into new flatbuffer.
FlatBufferBuilder fbb = new FlatBufferBuilder(1);
fbb.Finish(Monster.Pack(fbb, monsterobj).Value);Json Serialization
An additional feature of the object API is the ability to allow you to
serialize & deserialize a JSON text.
To use Json Serialization, add --cs-gen-json-serializer option to flatc and
add Newtonsoft.Json nuget package to csproj. This requires explicitly setting
the --gen-object-api option as well.
// Deserialize MonsterT from json
string jsonText = File.ReadAllText(@"Resources/monsterdata_test.json");
MonsterT mon = MonsterT.DeserializeFromJson(jsonText);
// Serialize MonsterT to json
string jsonText2 = mon.SerializeToJson();- Limitation
hashattribute currently not supported.
- NuGet package Dependency
Conditional compilation symbols
There are three conditional compilation symbols that have an impact on
performance/features of the C# ByteBuffer implementation.
UNSAFE_BYTEBUFFERThis will use unsafe code to manipulate the underlying byte array. This can
yield a reasonable performance increase.BYTEBUFFER_NO_BOUNDS_CHECKThis will disable the bounds check asserts to the byte array. This can yield a
small performance gain in normal code.ENABLE_SPAN_TThis will enable reading and writing blocks of memory with a
Span<T>instead
of justT[]. You can also enable writing directly to shared memory or other
types of memory by providing a custom implementation ofByteBufferAllocator.ENABLE_SPAN_Talso requiresUNSAFE_BYTEBUFFERto be defined, or .NET
Standard 2.1.
Using UNSAFE_BYTEBUFFER and BYTEBUFFER_NO_BOUNDS_CHECK together can yield a
performance gain of ~15% for some operations, however doing so is potentially
dangerous. Do so at your own risk!
File: docs/source/languages/cpp.md
Language Guide: C++
Before you get started
Before diving into the FlatBuffers usage in C++, it should be noted that
the Tutorial page has a complete guide
to general FlatBuffers usage in all of the supported languages (including C++).
This page is designed to cover the nuances of FlatBuffers usage, specific to
C++.
Prerequisites
This page assumes you have written a FlatBuffers schema and compiled it
with the Schema Compiler. If you have not, please see
Using the schema compiler
and Writing a schema.
Assuming you wrote a schema, say mygame.fbs (though the extension doesn't
matter), you've generated a C++ header called mygame_generated.h using the
compiler (e.g. flatc -c mygame.fbs), you can now start using this in
your program by including the header. As noted, this header relies onflatbuffers/flatbuffers.h, which should be in your include path.
FlatBuffers C++ library code location
The code for the FlatBuffers C++ library can be found atflatbuffers/include/flatbuffers. You can browse the library code on the
FlatBuffers GitHub page.
Testing the FlatBuffers C++ library
The code to test the C++ library can be found at flatbuffers/tests.
The test code itself is located in
test.cpp.
This test file is built alongside flatc. To review how to build the project,
please read the Building documentation.
To run the tests, execute flattests from the root flatbuffers/ directory.
For example, on Linux, you would simply
run: ./flattests.
Using the FlatBuffers C++ library
Note: See Tutorial for a more in-depth
example of how to use FlatBuffers in C++.
FlatBuffers supports both reading and writing FlatBuffers in C++.
To use FlatBuffers in your code, first generate the C++ classes from your
schema with the --cpp option to flatc. Then you can include both FlatBuffers
and the generated code to read or write FlatBuffers.
For example, here is how you would read a FlatBuffer binary file in C++:
First, include the library and generated code. Then read the file into
a char * array, which you pass to GetMonster().
#include "flatbuffers/flatbuffers.h"
#include "monster_test_generated.h"
#include // C++ header file for printing
#include <fstream> // C++ header file for file access
std::ifstream infile;
infile.open("monsterdata_test.mon", std::ios::binary | std::ios::in);
infile.seekg(0,std::ios::end);
int length = infile.tellg();
infile.seekg(0,std::ios::beg);
char *data = new char[length];
infile.read(data, length);
infile.close();
auto monster = GetMonster(data);monster is of type Monster *, and points to somewhere inside your
buffer (root object pointers are not the same as buffer_pointer !).
If you look in your generated header, you'll see it has
convenient accessors for all fields, e.g. hp(), mana(), etc:
std::cout << "hp : " << monster->hp() << std::endl; // '80'
std::cout << "mana : " << monster->mana() << std::endl; // default value of '150'
std::cout << "name : " << monster->name()->c_str() << std::endl; // "MyMonster"Note: That we never stored a mana value, so it will return the default.
The following attributes are supported:
shared(on a field): For string fields, this enables the usage of string
pooling (i.e.CreateSharedString) as default serialization behavior.Specifically,
CreateXxxDirectfunctions andPackfunctions for object
based API (see below) will useCreateSharedStringto create strings.
Object based API
FlatBuffers is all about memory efficiency, which is why its base API is written
around using as little as possible of it. This does make the API clumsier
(requiring pre-order construction of all data, and making mutation harder).
For times when efficiency is less important a more convenient object based API
can be used (through --gen-object-api) that is able to unpack & pack a
FlatBuffer into objects and standard STL containers, allowing for convenient
construction, access and mutation.
To use:
// Autogenerated class from table Monster.
MonsterT monsterobj;
// Deserialize from buffer into object.
GetMonster(flatbuffer)->UnPackTo(&monsterobj);
// Update object directly like a C++ class instance.
cout << monsterobj.name; // This is now a std::string!
monsterobj.name = "Bob"; // Change the name.
// Serialize into new flatbuffer.
FlatBufferBuilder fbb;
fbb.Finish(Monster::Pack(fbb, &monsterobj));The following attributes are specific to the object-based API code generation:
native_inline(on a field): Because FlatBuffer tables and structs are
optionally present in a given buffer, they are best represented as pointers
(specifically std::unique_ptrs) in the native class since they can be null.
This attribute changes the member declaration to use the type directly
rather than wrapped in a unique_ptr.native_default("value")(on a field): For members that are declared
"native_inline", the value specified with this attribute will be included
verbatim in the class constructor initializer list for this member.native_custom_alloc("custom_allocator")(on a table or struct): When using the
object-based API all generated NativeTables that are allocated when unpacking
your flatbuffer will use "custom allocator". The allocator is also used by
any std::vector that appears in a table defined withnative_custom_alloc.
This can be used to provide allocation from a pool for example, for faster
unpacking when using the object-based API.
Minimal Example:
schema:
table mytable(native_custom_alloc:"custom_allocator") {
...
}with custom_allocator defined before flatbuffers.h is included, as:
template <typename T> struct custom_allocator : public std::allocator<T> {
typedef T *pointer;
template <class U>
struct rebind {
typedef custom_allocator other;
};
pointer allocate(const std::size_t n) {
return std::allocator<T>::allocate(n);
}
void deallocate(T* ptr, std::size_t n) {
return std::allocator<T>::deallocate(ptr,n);
}
custom_allocator() throw() {}
template <class U>
custom_allocator(const custom_allocator&) throw() {}
};native_type("type")(on a struct): In some cases, a more optimal C++ data
type exists for a given struct. For example, the following schema:
struct Vec2 {
x: float;
y: float;
}generates the following Object-Based API class:
struct Vec2T : flatbuffers::NativeTable {
float x;
float y;
};However, it can be useful to instead use a user-defined C++ type since it
can provide more functionality, eg.
struct vector2 {
float x = 0, y = 0;
vector2 operator+(vector2 rhs) const { ... }
vector2 operator-(vector2 rhs) const { ... }
float length() const { ... }
// etc.
};The native_type attribute will replace the usage of the generated class
with the given type. So, continuing with the example, the generated
code would use vector2 in place of Vec2T for all generated code of
the Object-Based API.
However, because the native_type is unknown to flatbuffers, the user must
provide the following functions to aide in the serialization process:
namespace flatbuffers {
Vec2 Pack(const vector2& obj);
vector2 UnPack(const Vec2& obj);
}native_type_pack_name("name")(on a struct whennative_typeis
specified, too): when you want to use the samenative_typemultiple times
(e. g. with different precision) you must make the names of the Pack/UnPack
functions unique, otherwise you will run into compile errors. This attribute
appends a name to the expected Pack/UnPack functions. So when you
specifynative_type_pack_name("Vec2")in the above example you now need to
implement these serialization functions instead:
namespace flatbuffers {
Vec2 PackVec2(const vector2& obj);
vector2 UnPackVec2(const Vec2& obj);
}native_type("type")(on a table): Tables can also be represented with
native types. For example, the following schema:
table Matrix (native_type: "NativeMatrix") {
rows: int32;
columns: int32;
values: [float];
}Would be represented by a user-defined C++ class:
class NativeMatrix { ... }In this case, the following function declarations are generated by the compiler.
The user must provide and link the matching function definitions:
struct Matrix FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table {
// ...
static ::flatbuffers::Offset<Matrix> Pack(
::flatbuffers::FlatBufferBuilder& _fbb,
const NativeMatrix* _o,
const ::flatbuffers::rehasher_function_t* _rehasher = nullptr);
void UnPackTo(
NativeMatrix* _o,
const ::flatbuffers::resolver_function_t* _resolver = nullptr) const;
}Finally, the following top-level attributes:
native_include("path")(at file level): Because thenative_typeattribute
can be used to introduce types that are unknown to flatbuffers, it may be
necessary to include "external" header files in the generated code. This
attribute can be used to directly add an #include directive to the top of
the generated code that includes the specified path directly.force_align: this attribute may not be respected in the object API,
depending on the aligned of the allocator used withnew.
External references
An additional feature of the object API is the ability to allow you to load
multiple independent FlatBuffers, and have them refer to eachothers objects
using hashes which are then represented as typed pointers in the object API.
To make this work have a field in the objects you want to referred to which is
using the string hashing feature (see hash attribute in the
schema documentation). Then you have
a similar hash in the field referring to it, along with a cpp_type
attribute specifying the C++ type this will refer to (this can be any C++
type, and will get a * added).
Then, in JSON or however you create these buffers, make sure they use the
same string (or hash).
When you call UnPack (or Create), you'll need a function that maps from
hash to the object (see resolver_function_t for details).
Using different pointer types
By default the object tree is built out of std::unique_ptr, but you can
influence this either globally (using the --cpp-ptr-type argument toflatc) or per field (using the cpp_ptr_type attribute) to by any smart
pointer type (my_ptr<T>), or by specifying naked as the type to get T *
pointers. Unlike the smart pointers, naked pointers do not manage memory for
you, so you'll have to manage their lifecycles manually. To reference the
pointer type specified by the --cpp-ptr-type argument to flatc from a
flatbuffer field set the cpp_ptr_type attribute to default_ptr_type.
Using different string type
By default the object tree is built out of std::string, but you can
influence this either globally (using the --cpp-str-type argument toflatc) or per field using the cpp_str_type attribute.
The type must support T::c_str(), T::length() and T::empty() as member functions.
Further, the type must be constructible from std::string, as by default a
std::string instance is constructed and then used to initialize the custom
string type. This behavior impedes efficient and zero-copy construction of
custom string types; the --cpp-str-flex-ctor argument to flatc or the
per field attribute cpp_str_flex_ctor can be used to change this behavior,
so that the custom string type is constructed by passing the pointer and
length of the FlatBuffers String. The custom string class will require a
constructor in the following format: custom_str_class(const char *, size_t).
Please note that the character array is not guaranteed to be NULL terminated,
you should always use the provided size to determine end of string.
Reflection (& Resizing)
There is experimental support for reflection in FlatBuffers, allowing you to
read and write data even if you don't know the exact format of a buffer, and
even allows you to change sizes of strings and vectors in-place.
The way this works is very elegant; there is actually a FlatBuffer schema that
describes schemas (!) which you can find in reflection/reflection.fbs.
The compiler, flatc, can write out any schemas it has just parsed as a binary
FlatBuffer, corresponding to this meta-schema.
Loading in one of these binary schemas at runtime allows you traverse any
FlatBuffer data that corresponds to it without knowing the exact format. You
can query what fields are present, and then read/write them after.
For convenient field manipulation, you can include the headerflatbuffers/reflection.h which includes both the generated code from the meta
schema, as well as a lot of helper functions.
And example of usage, for the time being, can be found intest.cpp/ReflectionTest().
Mini Reflection
A more limited form of reflection is available for direct inclusion in
generated code, which doesn't do any (binary) schema access at all. It was designed
to keep the overhead of reflection as low as possible (on the order of 2-6
bytes per field added to your executable), but doesn't contain all the
information the (binary) schema contains.
You add this information to your generated code by specifying --reflect-types
(or instead --reflect-names if you also want field / enum names).
You can now use this information, for example to print a FlatBuffer to text:
auto s = flatbuffers::FlatBufferToString(flatbuf, MonsterTypeTable());MonsterTypeTable() is declared in the generated code for each type. The
string produced is very similar to the JSON produced by the Parser based
text generator.
You'll need flatbuffers/minireflect.h for this functionality. In there is also
a convenient visitor/iterator so you can write your own output / functionality
based on the mini reflection tables without having to know the FlatBuffers or
reflection encoding.
Storing maps / dictionaries in a FlatBuffer
FlatBuffers doesn't support maps natively, but there is support to
emulate their behavior with vectors and binary search, which means you
can have fast lookups directly from a FlatBuffer without having to unpack
your data into a std::map or similar.
To use it:
- Designate one of the fields in a table as they "key" field. You do this
by setting thekeyattribute on this field, e.g.name:string (key).
You may only have one key field, and it must be of string or scalar type. - Write out tables of this type as usual, collect their offsets in an
array or vector. - Instead of
CreateVector, callCreateVectorOfSortedTables,
which will first sort all offsets such that the tables they refer to
are sorted by the key field, then serialize it. - Now when you're accessing the FlatBuffer, you can use
Vector::LookupByKey
instead of justVector::Getto access elements of the vector, e.g.:myvector->LookupByKey("Fred"), which returns a pointer to the
corresponding table type, ornullptrif not found.LookupByKeyperforms a binary search, so should have a similar speed tostd::map, though may be faster because of better caching.LookupByKey
only works if the vector has been sorted, it will likely not find elements
if it hasn't been sorted.
Direct memory access
As you can see from the above examples, all elements in a buffer are
accessed through generated accessors. This is because everything is
stored in little endian format on all platforms (the accessor
performs a swap operation on big endian machines), and also because
the layout of things is generally not known to the user.
For structs, layout is deterministic and guaranteed to be the same
across platforms (scalars are aligned to their
own size, and structs themselves to their largest member), and you
are allowed to access this memory directly by using sizeof() andmemcpy on the pointer to a struct, or even an array of structs.
To compute offsets to sub-elements of a struct, make sure they
are a structs themselves, as then you can use the pointers to
figure out the offset without having to hardcode it. This is
handy for use of arrays of structs with calls like glVertexAttribPointer
in OpenGL or similar APIs.
It is important to note is that structs are still little endian on all
machines, so only use tricks like this if you can guarantee you're not
shipping on a big endian machine (an assert(FLATBUFFERS_LITTLEENDIAN)
would be wise).
Access of untrusted buffers
The generated accessor functions access fields over offsets, which is
very quick. These offsets are not verified at run-time, so a malformed
buffer could cause a program to crash by accessing random memory.
When you're processing large amounts of data from a source you know (e.g.
your own generated data on disk), this is acceptable, but when reading
data from the network that can potentially have been modified by an
attacker, this is undesirable.
For this reason, you can optionally use a buffer verifier before you
access the data. This verifier will check all offsets, all sizes of
fields, and null termination of strings to ensure that when a buffer
is accessed, all reads will end up inside the buffer.
Each root type will have a verification function generated for it,
e.g. for Monster, you can call:
Verifier verifier(buf, len);
bool ok = VerifyMonsterBuffer(verifier);if ok is true, the buffer is safe to read.
Besides untrusted data, this function may be useful to call in debug
mode, as extra insurance against data being corrupted somewhere along
the way.
While verifying a buffer isn't "free", it is typically faster than
a full traversal (since any scalar data is not actually touched),
and since it may cause the buffer to be brought into cache before
reading, the actual overhead may be even lower than expected.
In specialized cases where a denial of service attack is possible,
the verifier has two additional constructor arguments that allow
you to limit the nesting depth and total amount of tables the
verifier may encounter before declaring the buffer malformed. The default isVerifier(buf, len, 64 /* max depth */, 1000000, /* max tables */) which
should be sufficient for most uses.
Text & schema parsing
Using binary buffers with the generated header provides a super low
overhead use of FlatBuffer data. There are, however, times when you want
to use text formats, for example because it interacts better with source
control, or you want to give your users easy access to data.
Another reason might be that you already have a lot of data in JSON
format, or a tool that generates JSON, and if you can write a schema for
it, this will provide you an easy way to use that data directly.
(see the schema documentation for some specifics on the JSON format
accepted).
Schema evolution compatibility for the JSON format follows the same rules as the binary format (JSON formatted data will be forwards/backwards compatible with schemas that evolve in a compatible way).
There are two ways to use text formats:
Using the compiler as a conversion tool
This is the preferred path, as it doesn't require you to add any new
code to your program, and is maximally efficient since you can ship with
binary data. The disadvantage is that it is an extra step for your
users/developers to perform, though you might be able to automate it.
flatc -b myschema.fbs mydata.jsonThis will generate the binary file mydata_wire.bin which can be loaded
as before.
Making your program capable of loading text directly
This gives you maximum flexibility. You could even opt to support both,
i.e. check for both files, and regenerate the binary from text when
required, otherwise just load the binary.
This option is currently only available for C++, or Java through JNI.
As mentioned in the section "Building" above, this technique requires
you to link a few more files into your program, and you'll want to includeflatbuffers/idl.h.
Load text (either a schema or json) into an in-memory buffer (there is a
convenient LoadFile() utility function in flatbuffers/util.h if you
wish). Construct a parser:
flatbuffers::Parser parser;Now you can parse any number of text files in sequence:
parser.Parse(text_file.c_str());This works similarly to how the command-line compiler works: a sequence
of files parsed by the same Parser object allow later files to
reference definitions in earlier files. Typically this means you first
load a schema file (which populates Parser with definitions), followed
by one or more JSON files.
As optional argument to Parse, you may specify a null-terminated list of
include paths. If not specified, any include statements try to resolve from
the current directory.
If there were any parsing errors, Parse will return false, andParser::error_ contains a human readable error string with a line number
etc, which you should present to the creator of that file.
After each JSON file, the Parser::fbb member variable is theFlatBufferBuilder that contains the binary buffer version of that
file, that you can access as described above.
samples/sample_text.cpp is a code sample showing the above operations.
Threading
Reading a FlatBuffer does not touch any memory outside the original buffer,
and is entirely read-only (all const), so is safe to access from multiple
threads even without synchronisation primitives.
Creating a FlatBuffer is not thread safe. All state related to building
a FlatBuffer is contained in a FlatBufferBuilder instance, and no memory
outside of it is touched. To make this thread safe, either do not
share instances of FlatBufferBuilder between threads (recommended), or
manually wrap it in synchronisation primitives. There's no automatic way to
accomplish this, by design, as we feel multithreaded construction
of a single buffer will be rare, and synchronisation overhead would be costly.
Advanced union features
The C++ implementation currently supports vectors of unions (i.e. you can
declare a field as [T] where T is a union type instead of a table type). It
also supports structs and strings in unions, besides tables.
For an example of these features, see tests/union_vector, andUnionVectorTest in test.cpp.
Since these features haven't been ported to other languages yet, if you
choose to use them, you won't be able to use these buffers in other languages
(flatc will refuse to compile a schema that uses these features).
These features reduce the amount of "table wrapping" that was previously
needed to use unions.
To use scalars, simply wrap them in a struct.
Depth limit of nested objects and stack-overflow control
The parser of Flatbuffers schema or json-files is kind of recursive parser.
To avoid stack-overflow problem the parser has a built-in limiter of
recursion depth. Number of nested declarations in a schema or number of
nested json-objects is limited. By default, this depth limit set to 64.
It is possible to override this limit with FLATBUFFERS_MAX_PARSING_DEPTH
definition. This definition can be helpful for testing purposes or embedded
applications. For details see build of
CMake-based projects.
Dependence from C-locale {#flatbuffers_locale_cpp}
The Flatbuffers grammar uses ASCII
character set for identifiers, alphanumeric literals, reserved words.
Internal implementation of the Flatbuffers depends from functions which
depend from C-locale: strtod() or strtof(), for example.
The library expects the dot . symbol as the separator of an integer
part from the fractional part of a float number.
Another separator symbols (, for example) will break the compatibility
and may lead to an error while parsing a Flatbuffers schema or a json file.
The Standard C locale is a global resource, there is only one locale for
the entire application. Some modern compilers and platforms have
locale-independent or locale-narrow functions strtof_l, strtod_l,strtoll_l, strtoull_l to resolve this dependency.
These functions use specified locale rather than the global or per-thread
locale instead. They are part of POSIX-2008 but not part of the C/C++
standard library, therefore, may be missing on some platforms.
The Flatbuffers library try to detect these functions at configuration and
compile time:
- CMake
"CMakeLists.txt":- Check existence of
strtol_landstrtod_lin the<stdlib.h>.
- Check existence of
- Compile-time
"/include/base.h":_MSC_VER >= 1900: MSVC2012 or higher if build with MSVC._XOPEN_SOURCE>=700: POSIX-2008 if build with GCC/Clang.
After detection, the definition FLATBUFFERS_LOCALE_INDEPENDENT will be
set to 0 or 1.
To override or stop this detection use CMake -DFLATBUFFERS_LOCALE_INDEPENDENT={0|1}
or predefine FLATBUFFERS_LOCALE_INDEPENDENT symbol.
To test the compatibility of the Flatbuffers library with
a specific locale use the environment variable FLATBUFFERS_TEST_LOCALE:
>FLATBUFFERS_TEST_LOCALE="" ./flattests
>FLATBUFFERS_TEST_LOCALE="ru_RU.CP1251" ./flattestsSupport of floating-point numbers
The Flatbuffers library assumes that a C++ compiler and a CPU are
compatible with the IEEE-754 floating-point standard.
The schema and json parser may fail if fast-math or /fp:fast mode is active.
Support of hexadecimal and special floating-point numbers
According to the grammar fbs and json files
may use hexadecimal and special (NaN, Inf) floating-point literals.
The Flatbuffers uses strtof and strtod functions to parse floating-point
literals. The Flatbuffers library has a code to detect a compiler compatibility
with the literals. If necessary conditions are met the preprocessor constantFLATBUFFERS_HAS_NEW_STRTOD will be set to 1.
The support of floating-point literals will be limited at compile time
if FLATBUFFERS_HAS_NEW_STRTOD constant is less than 1.
In this case, schemas with hexadecimal or special literals cannot be used.
Comparison of floating-point NaN values
The floating-point NaN (not a number) is special value which
representing an undefined or unrepresentable value.NaN may be explicitly assigned to variables, typically as a representation
for missing values or may be a result of a mathematical operation.
The IEEE-754 defines two kind of NaNs:
- Quiet NaNs, or
qNaNs. - Signaling NaNs, or
sNaNs.
According to the IEEE-754, a comparison with NaN always returns
an unordered result even when compared with itself. As a result, a whole
Flatbuffers object will be not equal to itself if has one or more NaN.
Flatbuffers scalar fields that have the default value are not actually stored
in the serialized data but are generated in code (see Writing a schema).
Scalar fields with NaN defaults break this behavior.
If a schema has a lot of NaN defaults the Flatbuffers can override
the unordered comparison by the ordered: (NaN==NaN)->true.
This ordered comparison is enabled when compiling a program with the symbolFLATBUFFERS_NAN_DEFAULTS defined.
Additional computations added by FLATBUFFERS_NAN_DEFAULTS are very cheap
if GCC or Clang used. These compilers have a compile-time implementation
of isnan checking which MSVC does not.
gRPC
Before you get started
Before diving into the FlatBuffers gRPC usage in C++, you should already be
familiar with the following:
- FlatBuffers as a serialization format
- gRPC usage
Using the FlatBuffers gRPC C++ library
NOTE: The examples below are also in the grpc/samples/greeter directory.
We will illustrate usage with the following schema:
--8<-- "https://raw.githubusercontent.com/google/flatbuffers/refs/heads/master/grpc/samples/greeter/greeter.fbs"When we run flatc, we pass in the --grpc option and generage an additionalgreeter.grpc.fb.h and greeter.grpc.fb.cc.
Example server code looks like this:
--8<-- "https://raw.githubusercontent.com/google/flatbuffers/refs/heads/master/grpc/samples/greeter/server.cpp"Example client code looks like this:
--8<-- "https://raw.githubusercontent.com/google/flatbuffers/refs/heads/master/grpc/samples/greeter/client.cpp"File: docs/source/languages/dart.md
Use in Dart {#flatbuffers_guide_use_dart}
Before you get started
Before diving into the FlatBuffers usage in Dart, it should be noted that
the Tutorial page has a complete guide
to general FlatBuffers usage in all of the supported languages (including Dart).
This page is designed to cover the nuances of FlatBuffers usage, specific to
Dart.
You should also have read the Building
documentation to build flatc and should be familiar with
Using the schema compiler and
Writing a schema.
FlatBuffers Dart library code location
The code for the FlatBuffers Dart library can be found atflatbuffers/dart. You can browse the library code on the FlatBuffers
GitHub page.
Testing the FlatBuffers Dart library
The code to test the Dart library can be found at flatbuffers/tests.
The test code itself is located in [dart_test.dart](https://github.com/google/
flatbuffers/blob/master/tests/dart_test.dart).
To run the tests, use the [DartTest.sh](https://github.com/google/flatbuffers/
blob/master/tests/DartTest.sh) shell script.
Note: The shell script requires the Dart SDK
to be installed.
Using the FlatBuffers Dart library
Note: See Tutorial for a more in-depth
example of how to use FlatBuffers in Dart.
FlatBuffers supports reading and writing binary FlatBuffers in Dart.
To use FlatBuffers in your own code, first generate Dart classes from your
schema with the --dart option to flatc. Then you can include both FlatBuffers
and the generated code to read or write a FlatBuffer.
For example, here is how you would read a FlatBuffer binary file in Dart: First,
include the library and generated code. Then read a FlatBuffer binary file into
a List, which you pass to the factory constructor for Monster:
import 'dart:io' as io;
import 'package:flat_buffers/flat_buffers.dart' as fb;
import './monster_my_game.sample_generated.dart' as myGame;
List data = await new io.File('monster.dat').readAsBytes();
var monster = new myGame.Monster(data);Now you can access values like this:
var hp = monster.hp;
var pos = monster.pos;Differences from the Dart SDK Front End flat_buffers
The work in this repository is signfiicantly based on the implementation used
internally by the Dart SDK in the front end/analyzer package. Several
significant changes have been made.
- Support for packed boolean lists has been removed. This is not standard
in other implementations and is not compatible with them. Do note that,
like in the JavaScript implementation, null values in boolean lists
will be treated as false. It is also still entirely possible to pack data
in a single scalar field, but that would have to be done on the application
side. - The SDK implementation supports enums with regular Dart enums, which
works if enums are always indexed at 1; however, FlatBuffers does not
require that. This implementation uses specialized enum-like classes to
ensure proper mapping from FlatBuffers to Dart and other platforms. - The SDK implementation does not appear to support FlatBuffer structs or
vectors of structs - it treated everything as a built-in scalar or a table.
This implementation treats structs in a way that is compatible with other
non-Dart implementations, and properly handles vectors of structs. Many of
the methods prefixed with 'low' have been prepurposed to support this. - The SDK implementation treats int64 and uint64 as float64s. This
implementation does not. This may cause problems with JavaScript
compatibility - however, it should be possible to use the JavaScript
implementation, or to do a customized implementation that treats all 64 bit
numbers as floats. Supporting the Dart VM and Flutter was a more important
goal of this implementation. Support for 16 bit integers was also added. - The code generation in this offers an "ObjectBuilder", which generates code
very similar to the SDK classes that consume FlatBuffers, as well as Builder
classes, which produces code which more closely resembles the builders in
other languages. The ObjectBuilder classes are easier to use, at the cost of
additional references allocated.
Text Parsing
There currently is no support for parsing text (Schema's and JSON) directly
from Dart, though you could use the C++ parser through Dart Native Extensions.
Please see the C++ documentation for more on text parsing (note that this is
not currently an option in Flutter - follow this issue
for the latest).
Object based API
FlatBuffers is all about memory efficiency, which is why its base API is written
around using as little as possible of it. This does make the API clumsier
(requiring pre-order construction of all data, and making mutation harder).
For times when efficiency is less important a more convenient object based API
can be used (through --gen-object-api) that is able to unpack & pack a FlatBuffer
into objects and lists, allowing for convenient construction, access and mutation.
To use:
// Deserialize from buffer into object.
MonsterT monster = Monster(flatbuffer).unpack();
// Update object directly like a Dart class instance.
print(monster.Name);
monster.Name = "Bob"; // Change the name.
// Serialize into new flatbuffer.
final fbb = Builder();
fbb.Finish(monster.pack(fbb));File: docs/source/languages/go.md
Use in Go {#flatbuffers_guide_use_go}
Before you get started
Before diving into the FlatBuffers usage in Go, it should be noted that
the Tutorial page has a complete guide
to general FlatBuffers usage in all of the supported languages (including Go).
This page is designed to cover the nuances of FlatBuffers usage, specific to
Go.
You should also have read the Building
documentation to build flatc and should be familiar with
Using the schema compiler and
Writing a schema.
FlatBuffers Go library code location
The code for the FlatBuffers Go library can be found atflatbuffers/go. You can browse the library code on the FlatBuffers
GitHub page.
Testing the FlatBuffers Go library
The code to test the Go library can be found at flatbuffers/tests.
The test code itself is located in [go_test.go](https://github.com/google/
flatbuffers/blob/master/tests/go_test.go).
To run the tests, use the [GoTest.sh](https://github.com/google/flatbuffers/
blob/master/tests/GoTest.sh) shell script.
Note: The shell script requires Go to
be installed.
Using the FlatBuffers Go library
Note: See Tutorial for a more in-depth
example of how to use FlatBuffers in Go.
FlatBuffers supports reading and writing binary FlatBuffers in Go.
To use FlatBuffers in your own code, first generate Go classes from your
schema with the --go option to flatc. Then you can include both FlatBuffers
and the generated code to read or write a FlatBuffer.
For example, here is how you would read a FlatBuffer binary file in Go: First,
include the library and generated code. Then read a FlatBuffer binary file into
a []byte, which you pass to the GetRootAsMonster function:
import (
example "MyGame/Example"
flatbuffers "github.com/google/flatbuffers/go"
"os"
)
buf, err := os.ReadFile("monster.dat")
// handle err
monster := example.GetRootAsMonster(buf, 0)Now you can access values like this:
hp := monster.Hp()
pos := monster.Pos(nil)In some cases it's necessary to modify values in an existing FlatBuffer in place (without creating a copy). For this reason, scalar fields of a Flatbuffer table or struct can be mutated.
monster := example.GetRootAsMonster(buf, 0)
// Set table field.
if ok := monster.MutateHp(10); !ok {
panic("failed to mutate Hp")
}
// Set struct field.
monster.Pos().MutateZ(4)
// This mutation will fail because the mana field is not available in
// the buffer. It should be set when creating the buffer.
if ok := monster.MutateMana(20); !ok {
panic("failed to mutate Hp")
}The term mutate is used instead of set to indicate that this is a special use case. All mutate functions return a boolean value which is false if the field we're trying to mutate is not available in the buffer.
Text Parsing
There currently is no support for parsing text (Schema's and JSON) directly
from Go, though you could use the C++ parser through cgo. Please see the
C++ documentation for more on text parsing.
File: docs/source/languages/java.md
Use in Java {#flatbuffers_guide_use_java}
Before you get started
Before diving into the FlatBuffers usage in Java, it should be noted that
the Tutorial page has a complete guide to
general FlatBuffers usage in all of the supported languages (including Java).
This page is designed to cover the nuances of FlatBuffers usage,
specific to Java.
You should also have read the Building
documentation to build flatc and should be familiar with
Using the schema compiler and
Writing a schema.
FlatBuffers Java code location
The code for the FlatBuffers Java library can be found atflatbuffers/java/com/google/flatbuffers. You can browse the library on the
[FlatBuffers GitHub page](https://github.com/google/flatbuffers/tree/master/
java/com/google/flatbuffers).
Testing the FlatBuffers Java libraries
The code to test the libraries can be found at flatbuffers/tests.
The test code for Java is located in [JavaTest.java](https://github.com/google
/flatbuffers/blob/master/tests/JavaTest.java).
To run the tests, use either [JavaTest.sh](https://github.com/google/
flatbuffers/blob/master/tests/JavaTest.sh) or [JavaTest.bat](https://github.com/
google/flatbuffers/blob/master/tests/JavaTest.bat), depending on your operating
system.
Note: These scripts require that Java
is installed.
Using the FlatBuffers Java library
Note: See Tutorial for a more in-depth
example of how to use FlatBuffers in Java.
FlatBuffers supports reading and writing binary FlatBuffers in Java.
To use FlatBuffers in your own code, first generate Java classes from your
schema with the --java option to flatc.
Then you can include both FlatBuffers and the generated code to read
or write a FlatBuffer.
For example, here is how you would read a FlatBuffer binary file in Java:
First, import the library and generated code. Then, you read a FlatBuffer binary
file into a byte[]. You then turn the byte[] into a ByteBuffer, which you
pass to the getRootAsMyRootType function:
import MyGame.Example.*;
import com.google.flatbuffers.FlatBufferBuilder;
// This snippet ignores exceptions for brevity.
File file = new File("monsterdata_test.mon");
RandomAccessFile f = new RandomAccessFile(file, "r");
byte[] data = new byte[(int)f.length()];
f.readFully(data);
f.close();
ByteBuffer bb = ByteBuffer.wrap(data);
Monster monster = Monster.getRootAsMonster(bb);Now you can access the data from the Monster monster:
short hp = monster.hp();
Vec3 pos = monster.pos();Storing dictionaries in a FlatBuffer
FlatBuffers doesn't support dictionaries natively, but there is support to
emulate their behavior with vectors and binary search, which means you
can have fast lookups directly from a FlatBuffer without having to unpack
your data into a Dictionary or similar.
To use it:
- Designate one of the fields in a table as the "key" field. You do this
by setting thekeyattribute on this field, e.g.name:string (key).
You may only have one key field, and it must be of string or scalar type. - Write out tables of this type as usual, collect their offsets in an
array. - Instead of calling standard generated method,
e.g.:Monster.createTestarrayoftablesVector,
callcreateSortedVectorOfTables(from theFlatBufferBuilderobject).
which will first sort all offsets such that the tables they refer to
are sorted by the key field, then serialize it. - Now when you're accessing the FlatBuffer, you can use
theByKeyaccessor to access elements of the vector, e.g.:monster.testarrayoftablesByKey("Frodo").
which returns an object of the corresponding table type,
ornullif not found.ByKeyperforms a binary search, so should have a similar
speed toDictionary, though may be faster because of better caching.ByKeyonly works if the vector has been sorted, it will
likely not find elements if it hasn't been sorted.
Text parsing
There currently is no support for parsing text (Schema's and JSON) directly
from Java, though you could use the C++ parser through native call
interfaces available to each language. Please see the
C++ documentation for more on text parsing.
File: docs/source/languages/javascript.md
Use in JavaScript {#flatbuffers_guide_use_javascript}
Before you get started
Before diving into the FlatBuffers usage in JavaScript, it should be noted that
the Tutorial page has a complete guide to
general FlatBuffers usage in all of the supported languages
(including JavaScript). This page is specifically designed to cover the nuances
of FlatBuffers usage in JavaScript.
You should also have read the Building
documentation to build flatc and should be familiar with
Using the schema compiler and
Writing a schema.
FlatBuffers JavaScript library code location
The generated code for the FlatBuffers JavaScript library can be found at
https://www.npmjs.com/package/flatbuffers. To use it from sources:
- Run
npm run compilefrom the main folder to generate JS files from TS. - In your project, install it as a normal dependency, using the flatbuffers
folder as the source.
Using the FlatBuffers JavaScript library
Note: See Tutorial for a more in-depth
example of how to use FlatBuffers.
Due to the complexity related with large amounts of JS flavors and module types,
native JS support has been replaced in 2.0 by transpilation from TypeScript.
Please look at TypeScript usage and
transpile your sources to desired JS flavor. The minimal steps to get up and
running with JS are:
- Generate TS files from
*.fbsby using the--tsoption. - Transpile resulting TS files to desired JS flavor using
tsc(see
https://www.typescriptlang.org/download for installation instructions).
// Note: These require functions are an example - use your desired module flavor.
var fs = require('fs');
var flatbuffers = require('../flatbuffers').flatbuffers;
var MyGame = require('./monster_generated').MyGame;
var data = new Uint8Array(fs.readFileSync('monster.dat'));
var buf = new flatbuffers.ByteBuffer(data);
var monster = MyGame.Example.Monster.getRootAsMonster(buf);
//--------------------------------------------------------------------------//
// Note: This code is an example of browser-based HTML/JavaScript. See above
// for the code using JavaScript module loaders (e.g. Node.js).
<script src="../js/flatbuffers.js"></script>
<script src="monster_generated.js"></script>
<script>
function readFile() {
var reader = new FileReader(); // This example uses the HTML5 FileReader.
var file = document.getElementById(
'file_input').files[0]; // "monster.dat" from the HTML field.
reader.onload = function() { // Executes after the file is read.
var data = new Uint8Array(reader.result);
var buf = new flatbuffers.ByteBuffer(data);
var monster = MyGame.Example.Monster.getRootAsMonster(buf);
}
reader.readAsArrayBuffer(file);
}
</script>
// Open the HTML file in a browser and select "monster.dat" from with the
// field.Now you can access values like this:
var hp = monster.hp();
var pos = monster.pos();Text parsing FlatBuffers in JavaScript
There currently is no support for parsing text (Schema's and JSON) directly
from JavaScript.