FlatBuffers 快速指南



FlatBuffers - 简介

在深入了解 FlatBuffers 之前,让我们先简要回顾一下序列化,这是 FlatBuffers 所做的工作。

什么是序列化和反序列化?

每当我们需要将对象状态持久化到内存系统时,都需要序列化。在序列化中,我们将对象转换为字节,并将这些字节存储在内存系统中。这些存储的字节随后可以被反序列化以恢复对象状态。由于我们将对象转换为字节,因此可以将其存储在任何地方,包括文件系统、消息队列、数据库等等,然后我们可以将这些字节传输到不同的机器并检索对象状态。

为什么我们需要序列化和反序列化?

序列化有助于持久化对象状态,然后我们可以将其传输到网络上的任何位置。接收后,我们可以反序列化对象,或者换句话说,我们可以随时在不同的机器上从字节恢复我们的对象。这是序列化和反序列化的许多重要用例之一。另一个重要用例是对象需要通过网络传输的情况。消息队列、数据库对象、REST API 都遵循此原则。在这种情况下,发送方首先序列化对象,然后将其传输到接收方。接收方然后反序列化已序列化的对象。

在 REST API、微服务架构中,应用程序通常被分解成小的服务,这些服务通过消息队列和 API 相互通信。由于通信是通过网络进行的,需要频繁地将对象转换为字节,然后再转换回对象。因此,序列化和反序列化在分布式环境中变得非常关键。

为什么选择 FlatBuffers?

Google FlatBuffers 执行将对象序列化和反序列化为字节的操作,这些字节可以跨网络传输。但也有一些其他的库和机制可以传输数据。

那么,是什么让 FlatBuffers 如此特别呢?以下是一些重要的特性:

  • 语言无关性 - FlatBuffers 编译器可以为多种语言创建代码,例如 Java、Python、Go、C、C++ 等。因此,Java 对象可以由 Java 程序序列化为字节,并且可以反序列化为 Python 对象,反之亦然。

  • 高效的数据压缩 - FlatBuffers API 最初是为游戏环境和性能关键型系统开发的,其设计考虑了数据压缩和性能。它非常节省内存,甚至比 Google Protocol Buffers(另一个 Google 序列化和反序列化库)更快。

  • 向前和向后兼容性 - FlatBuffers 架构同时具有向前和向后兼容性。FlatBuffers 的 schema 支持在较新代码中添加更改,并允许弃用较旧的更改,而不会破坏向后兼容性。

  • 易于使用 - FlatBuffers 库自动生成序列化代码(我们将在接下来的章节中看到),具有版本控制方案,以确保数据创建者和数据使用者可以拥有序列化定义的不同版本等。

  • JSON 可转换 FlatBuffers schema 文件可以转换为 JSON 文件,同样,我们可以使用 FlatBuffers schema 转换 JSON 文件。

FlatBuffers 与其他方案对比 (XML/JSON/Java 序列化)

让我们看看其他通过网络传输数据的方式与 FlatBuffers 相比如何。

特性 FlatBuffers JSON XML
语言无关性
序列化数据大小 三者中最小的 小于 XML 三者中最大的
人类可读性 否,因为它使用单独的编码 schema 是,因为它使用基于文本的格式 是,因为它使用基于文本的格式
序列化速度 三者中最快 快于 XML 三者中最慢
数据类型支持 比其他两者更丰富。支持复杂数据类型,如 Any、oneof 等。 支持基本数据类型 支持基本数据类型
对演变 schema 的支持

FlatBuffers - Schema

概述

现在让我们使用 Google FlatBuffers 并看看它如何与一个简单的问候应用程序一起工作。在这个例子中,我们将创建一个简单的应用程序,它将执行以下操作:

问候写入器

  • 从用户处获取问候语和用户名

  • 将上述信息存储在磁盘上的文件中

问候读取器

  • 读取我们在上面存储的文件

  • 将数据转换为对象并打印数据

FlatBuffers Schema 文件

FlatBuffers 的“schema 文件”包含我们要序列化的数据的 schema 定义。数据存储在具有扩展名“.fbs” 的人类可读文件中。

让我们将以下数据存储在greeting.fbs中,我们将在我们的第一个应用程序中使用它。

greeting.fbs

namespace com.tutorialspoint.greeting;

table Greet {
   greeting: string;
   username: string;
}

root_type Greet;

理解每个结构

namespace com.tutorialspoint.greeting;

这里的namespace用于.fbs文件生成的代码的包/命名空间声明。例如,我们生成的 Java 类将位于 com.tutorialspoint.greeting 包中。

table Greet

要创建/重新创建的对象的基础类的名称。

greeting: string;
username: string;

这些是Greet类的属性以及数据类型。

root_type Greet;

root_type 告诉 FlatBuffers 编译器根表是 Greet,它将是生成代码时的主类。

FlatBuffers 代码生成

现在我们已经定义了,让我们安装“flatc”二进制文件,我们将使用它来自动生成上述Greet类的代码。二进制文件可以在"https://github.com/google/flatbuffers/releases"找到。

根据操作系统选择正确的二进制文件。我们将在 Windows 上安装 FlatBuffers 编译器二进制文件,但 Linux 的步骤差别不大。

我们已下载https://github.com/google/flatbuffers/releases/download/v24.3.25/Windows.flatc.binary.zip

验证 FlatBuffers 编译器设置

安装后,确保您可以通过命令行访问它:

flatc --version

flatc version 24.3.25

这确认 Flatc 已正确安装。现在让我们继续为 Java 创建上面描述的问候应用程序。

Java 中的问候应用程序

现在我们已经安装了flatc,我们可以使用flatc从 .fbs 文件自动生成代码。让我们首先创建一个 Java 项目。

以下是我们将用于 Java 项目的 Maven 配置。请注意,它还包含flatc-java所需的库。

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	
   <modelVersion>4.0.0</modelVersion>
   <groupId>com.tutorialspoint.greeting</groupId>
   <artifactId>flatbuffers-tutorial</artifactId>
   <version>1.0</version>
   <packaging>jar</packaging>

   <properties>
      <maven.compiler.source>21</maven.compiler.source>
      <maven.compiler.target>21</maven.compiler.target>
   </properties>

   <dependencies>
      <!-- https://mvnrepository.com/artifact/com.google.flatbuffers/flatbuffers-java -->
      <dependency>
         <groupId>com.google.flatbuffers</groupId>
         <artifactId>flatbuffers-java</artifactId>
         <version>24.3.25</version>
      </dependency>
   </dependencies>

   <build>
      <plugins>
         <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <version>3.2.4</version>
            <configuration>
               <!--Put your configurations here-->
            </configuration>
            <executions>
               <execution>
                  <phase>package</phase>
                     <goals>
                     <goal>shade</goal>
                  </goals>
               </execution>
            </executions>
         </plugin>
      </plugins>
   </build>
</project>

我们所有的代码都将位于src/main/java下。

项目结构搭建完毕后,让我们生成Greet类的代码:

生成 Java 类

flatc --java greeting.fbs

命令执行后,您会在当前目录中的com > tutorialspoint > greeting文件夹下看到一个自动生成的类。

  • Greet.java

此文件包含一个Greet类,它将帮助我们对Greet对象进行序列化和反序列化。

使用生成的 Java 类

现在,让我们编写数据的写入器,它将接受用户名问候语作为输入:

GreetWriter.java

package com.tutorialspoint.greeting;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import com.google.flatbuffers.FlatBufferBuilder;

public class GreetWriter {
   public static void main(String[] args) throws FileNotFoundException, IOException {
      // create a flat buffer builder
      // it will be used to create Greet FlatBuffer
      FlatBufferBuilder builder = new FlatBufferBuilder(1024);

      // read greeting and username from console
      int greeting = builder.createString(args[0]);
      int username = builder.createString(args[1]);

      // create Greet FlatBuffers using startGreet() method
      Greet.startGreet(builder);
      // add the greeting and username to the Greet FlatBuffer
      Greet.addGreeting(builder, greeting);
      Greet.addUsername(builder, username);

      // mark end of data being entered in Greet FlatBuffer
      int greet = Greet.endGreet(builder);

      // finish the builder
      builder.finish(greet);

      // get the bytes to be stored
      byte[] data = builder.sizedByteArray();

      String filename = "greeting_flatbuffers_output";
      System.out.println("Saving greeting to file: " + filename);
      // write the builder content to the file named	greeting_flatbuffers_output
      try(FileOutputStream output = new FileOutputStream(filename)){
         output.write(data);
      }
      System.out.println("Saved greeting with following data to disk: \n" + greeting);
   }   
}

写入器简单地获取 CLI 参数,创建Greet对象,将其序列化,然后将其转储到文件中。

现在让我们编写一个读取器来读取文件:

GreetReader.java

package com.tutorialspoint.greeting;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.ByteBuffer;

public class GreetReader {
   public static void main(String[] args) throws FileNotFoundException, IOException {

      String filename = "greeting_flatbuffers_output";
      System.out.println("Reading from file " + filename);

      try(FileInputStream input = new FileInputStream(filename)) {
         // get the serialized data
         byte[] data = input.readAllBytes();
         ByteBuffer buf = ByteBuffer.wrap(data);
         // read the root object in serialized data
         Greet greet = Greet.getRootAsGreet(buf);

         // print greet values 
         System.out.println("Greeting: " + greet.greeting() + "\n" + "Username: " + greet.username());
      }
   }
}

读取器简单地从同一文件中读取,将其反序列化,并打印问候信息。

编译项目

现在我们已经设置了读取器写入器,让我们编译项目。

mvn clean install

序列化 Java 对象

现在,让我们首先执行写入器将对象序列化到文件系统。

java -cp .\target\flatbuffers-tutorial-1.0.jar com.tutorialspoint.greeting.GreetWriter Hello John

Saving greeting to file: 
greeting_protobuf_output

Saved greeting with following data to disk:
12

反序列化已序列化的对象

然后,让我们执行读取器从文件系统反序列化对象。

java -cp .\target\flatbuffers-tutorial-1.0.jar com.tutorialspoint.greeting.GreetReader

Reading from file greeting_protobuf_output
Greeting: Hello
Username: John

因此,正如我们看到的,写入器序列化并保存到文件的数据,被读取器正确地反序列化并相应地打印出来。

FlatBuffers - 结构

概述

现在让我们看看 Google FlatBuffers 提供的一些基本数据结构和数据类型。我们将使用电影院的例子来查看这些数据结构。

请注意,对于此结构,虽然我们将使用 Java 代码,但在 Python 代码中使用它们也应该同样简单且可行。

在接下来的几章中,我们将逐一讨论以下 FlatBuffers 数据类型:

数据类型

  • 表 (table) - “表”是 FlatBuffers 的一个非常基本的基础构件。它在我们使用的语言(例如 Java、Python 等)中转换为类

  • 字符串 (string) - “字符串”数据类型在我们使用的语言(例如 Java、Python 等)中转换为字符串

  • 数字 (Numbers) - 数字包括 FlatBuffers 类型,如 int、short、float、double,它们是 Protobuf 的基本构建块。它在我们使用的语言(例如 Java、Python 等)中分别转换为 int、long、float、double。我们也可以使用别名,如 int16 代表 short,float32 代表 float 等。

  • 布尔值 (bool) - “布尔值”数据类型是 FlatBuffers 的基本构建块之一。它在我们使用的语言(例如 Java、Python 等)中转换为布尔值。

  • 枚举 (enum) − “enum” 是 FlatBuffers 的复合数据类型之一。它在我们使用的语言中被翻译成枚举,例如 Java。

  • 向量 (vector) − 使用 [] 符号创建向量或数组,它是 FlatBuffers 的复合数据类型之一。FlatBuffers 向量类似于 Java 数组。

  • 结构体 (struct) − “struct” 是 FlatBuffers 的复合数据类型之一。它用于创建不可修改的标量值集合。struct 使用更少的内存,并且查找速度非常快。

  • 嵌套类 − 我们可以将使用 "table" 创建的类嵌套在另一个 "table" 中,从而创建嵌套类。

  • 联合体 (union) − “union” 用于创建一个可以接受任何不同类型值的结构。

FlatBuffers - 表

概述

FlatBuffers 的最基本构建块是表 (table) 属性。这相当于我们在使用的语言中的类 (class),例如 Java、Python 等。

示例代码

以下是我们需要使用的语法,用于指示 FlatBuffers 我们将创建给定表的实例:

namespace com.tutorialspoint.theater;

table Theater {
}
root_type Theater;

我们将以上内容保存到“theater.fbs”中,并在我们探索其他数据结构时使用它。

解释

namespace com.tutorialspoint.theater;

此参数特定于 Java,即“.fbs”文件生成的代码所在的包。Theater 类将创建在com.tutorialpoint.theater包中。

接下来,我们创建一个表 Theater:

table Theater

这只不过是将要创建/重新创建的对象的基类的类名。请注意,它在当前形式下是无用的,因为它没有任何其他属性。但是,随着我们的推进,我们将添加更多属性。

使用多个 table 属性

单个 fbs 文件也可以包含多个表。例如,如果需要,我们可以在同一个文件中添加一个Visitor表。FlatBuffers 将确保 Theater 类使用 root_type 属性保持为主类。例如:

namespace com.tutorialspoint.theater;

table Theater {
}

table Visitor {
}
root_type Theater;

从 fbs 文件创建 Java 类

要使用 FlatBuffers,我们现在必须使用flatc二进制文件从这个“.fbs”文件创建所需的类。让我们看看如何做到这一点:

flat  --java theater.fbs

使用从 fbs 文件创建的 Java 类

就是这样!以上命令应该在当前目录中创建所需的文件,现在我们可以在 Java 代码中使用它们:

// Create a FlatBuffer Builder with default buffer
FlatBufferBuilder builder = new FlatBufferBuilder(1024);

// Create Theater FlatBuffers using startTheater() method
Theater.startTheater(builder);

在这个阶段,它不是很有用,因为我们还没有向表中添加任何属性。当我们在Flat Buffers - string章节中查看字符串时,我们将进行此操作。

FlatBuffers - 字符串

概述

FlatBuffers 字符串在我们使用的语言中被翻译成字符串,例如 Java、Python 等。继续theater示例,以下是我们需要使用的语法,用于指示 FlatBuffers 我们将创建一个字符串

theater.fbs

namespace com.tutorialspoint.theater;

table Theater {
   name:string;
   address:string;
}
root_type Theater;

现在我们的包含两个字符串属性。每个属性的默认值为 null。

从 fbs 文件创建 Java 类

要使用 FlatBuffers,我们现在必须使用flatc二进制文件从这个“.fbs”文件创建所需的类。让我们看看如何做到这一点:

flatc  --java theater.fbs

这将在当前目录中的com > tutorialspoint > theater文件夹中创建一个 Theater.java 类。我们像在Flat Buffers - Schema章节中所做的那样,在我们的应用程序中使用此类。

使用从 fbs 文件创建的 Java 类

首先,让我们创建一个写入器 (writer)来写入theater信息:

TheaterWriter.java

package com.tutorialspoint.theater;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import com.google.flatbuffers.FlatBufferBuilder;

public class TheaterWriter {
   public static void main(String[] args) throws FileNotFoundException, IOException {
      // create a flat buffer builder
      // it will be used to create Theater FlatBuffer
      FlatBufferBuilder builder = new FlatBufferBuilder(1024);

      int name = builder.createString("Silver Screener");
      int address = builder.createString("212, Maple Street, LA, California");

      // create theater FlatBuffers using startTheater() method
      Theater.startTheater(builder);
      // add the name and address to the Theater FlatBuffer
      Theater.addName(builder, name);
      Theater.addAddress(builder, address);

      // mark end of data being entered in Greet FlatBuffer
      int theater = Theater.endTheater(builder);

      // finish the builder
      builder.finish(theater);

      // get the bytes to be stored
      byte[] data = builder.sizedByteArray();

      String filename = "theater_flatbuffers_output";
      System.out.println("Saving theater to file: " + filename);
      // write the builder content to the file named theater_flatbuffers_output
      try(FileOutputStream output = new FileOutputStream(filename)){
         output.write(data);
      }
      System.out.println("Saved theater with following data to disk: \n" + theater);
   }
}	

接下来,我们将有一个读取器 (reader)来读取theater信息:

TheaterReader.java

package com.tutorialspoint.theater;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.ByteBuffer;

public class TheaterReader {
   public static void main(String[] args) throws FileNotFoundException, IOException {

      String filename = "theater_flatbuffers_output";
      System.out.println("Reading from file " + filename);
      try(FileInputStream input = new FileInputStream(filename)) {
         // get the serialized data
         byte[] data = input.readAllBytes();
         ByteBuffer buf = ByteBuffer.wrap(data);
         // read the root object in serialized data
         Theater theater = Theater.getRootAsTheater(buf);
         // print theater values 
         System.out.println("Name: " + theater.name() + "\n" + "Address: " + theater.address());
      }
   }
}

编译项目

现在我们已经设置了读取器写入器,让我们编译项目。

mvn clean install

序列化 Java 对象

现在,编译后,让我们先执行写入器

java -cp .\target\flatbuffers-tutorial-1.0.jar com.tutorialspoint.theater.TheaterWriter

Saving theater to file: theater_flatbuffers_output
Saved theater with following data to disk:
72

反序列化已序列化的对象

现在,让我们执行读取器从同一个文件读取:

java -cp .\target\flatbuffers-tutorial-1.0.jar com.tutorialspoint.theater.TheaterReader

Reading from file theater_flatbuffers_output
Name: Silver Screener
Address: 212, Maple Street, LA, California

因此,正如我们所看到的,我们能够通过将二进制数据反序列化为Theater对象来读取序列化后的字符串。在下一章Flat Buffers - Numbers中,我们将了解数字

FlatBuffers - 数字

概述

数字包括 flatbuffers 类型,如int、short、float、double,它们是 FlatBuffers 的基本构建块。它们分别在我们使用的语言中被翻译成int、short、float、double,例如 Java、Python 等。

继续我们来自Flat Buffers - String章节的theater示例,以下是我们需要使用的语法,用于指示 FlatBuffers 我们将创建数字

theater.fbs

namespace com.tutorialspoint.theater;

table Theater {
   total_capcity:int;
   mobile:long;
   base_ticket_price:float;
}
root_type Theater;

现在我们的包含数值属性。默认值为 0 或 0.0(视情况而定)。

从 FBS 文件创建 Java 类

要使用 FlatBuffers,我们现在必须使用flatc二进制文件从这个“.fbs”文件创建所需的类。让我们看看如何做到这一点:

flatc  --java theater.fbs

这将在当前目录中的com > tutorialspoint > theater文件夹中创建一个 Theater.java 类。我们像在Flat Buffers - Schema章节中所做的那样,在我们的应用程序中使用此类。

<

使用从 fbs 文件创建的 Java 类

首先,让我们创建一个写入器 (writer)来写入theater信息:

TheaterWriter.java

package com.tutorialspoint.theater;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import com.google.flatbuffers.FlatBufferBuilder;

public class TheaterWriter {
   public static void main(String[] args) throws FileNotFoundException, IOException {
      // create a flat buffer builder
      // it will be used to create Theater FlatBuffer
      FlatBufferBuilder builder = new FlatBufferBuilder(1024);

      int totalCapacity = 320; 
      long mobile = 98234567189L;
      float baseTicketPrice = 22.45f;

      // create theater FlatBuffers using startTheater() method
      Theater.startTheater(builder);
      // add details to the Theater FlatBuffer
      Theater.addTotalCapcity(builder, totalCapacity);
      Theater.addMobile(builder, mobile);
      Theater.addBaseTicketPrice(builder, baseTicketPrice);

      // mark end of data being entered in Greet FlatBuffer
      int theater = Theater.endTheater(builder);

      // finish the builder
      builder.finish(theater);

      // get the bytes to be stored
      byte[] data = builder.sizedByteArray();

      String filename = "theater_flatbuffers_output";
      System.out.println("Saving theater to file: " + filename);
      // write the builder content to the file named theater_flatbuffers_output
      try(FileOutputStream output = new FileOutputStream(filename)){
         output.write(data);
      }
      System.out.println("Saved theater with following data to disk: \n" + theater);
   }
}	

接下来,我们将有一个读取器 (reader)来读取theater信息:

TheaterReader.java

package com.tutorialspoint.theater;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.ByteBuffer;

public class TheaterReader {
   public static void main(String[] args) throws FileNotFoundException, IOException {

      String filename = "theater_flatbuffers_output";
      System.out.println("Reading from file " + filename);
      try(FileInputStream input = new FileInputStream(filename)) {
         // get the serialized data
         byte[] data = input.readAllBytes();
         ByteBuffer buf = ByteBuffer.wrap(data);
         // read the root object in serialized data
         Theater theater = Theater.getRootAsTheater(buf);
         // print theater values 
         System.out.println("Total Capacity: " + theater.totalCapcity() 
            + "\n" + "Mobile: " + theater.mobile()
            + "\n" + "Base Ticket Price: " + theater.baseTicketPrice());
      }
   }
}

编译项目

现在我们已经设置了读取器写入器,让我们编译项目。

mvn clean install

序列化 Java 对象

现在,编译后,让我们先执行写入器

java -cp .\target\flatbuffers-tutorial-1.0.jar com.tutorialspoint.theater.TheaterWriter

Saving theater to file: theater_flatbuffers_output
Saved theater with following data to disk:
24

反序列化已序列化的对象

现在,让我们执行读取器从同一个文件读取:

java -cp .\target\flatbuffers-tutorial-1.0.jar com.tutorialspoint.theater.TheaterReader

Reading from file theater_flatbuffers_output
Total Capacity: 320
Mobile: 98234567189
Base Ticket Price: 22.45

因此,正如我们所看到的,我们能够通过将二进制数据反序列化为Theater对象来读取序列化后的字符串。在下一章Flat Buffers - bool中,我们将了解数字

FlatBuffers - 布尔值

概述

bool数据类型是 FlatBuffers 的基本构建块之一。它在我们使用的语言中被翻译成Boolean,例如JavaPython等。

继续我们来自Flat Buffers - String章节的theater示例,以下是我们需要使用的语法,用于指示 FlatBuffers 我们将创建bool

theater.fbs

namespace com.tutorialspoint.theater;

table Theater {
   drive_in:bool;
}
root_type Theater;

现在我们的包含一个bool属性。默认值为 false。

从 FBS 文件创建 Java 类

要使用 FlatBuffers,我们现在必须使用flatc二进制文件从这个“.fbs”文件创建所需的类。让我们看看如何做到这一点:

flatc  --java theater.fbs

这将在当前目录中的com > tutorialspoint > theater文件夹中创建一个 Theater.java 类。我们像在Flat Buffers - Schema章节中所做的那样,在我们的应用程序中使用此类。

使用从 fbs 文件创建的 Java 类

TheaterWriter.java

package com.tutorialspoint.theater;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import com.google.flatbuffers.FlatBufferBuilder;

public class TheaterWriter {
   public static void main(String[] args) throws FileNotFoundException, IOException {
      // create a flat buffer builder
      // it will be used to create Theater FlatBuffer
      FlatBufferBuilder builder = new FlatBufferBuilder(1024);

      boolean driveIn = true; 

      // create theater FlatBuffers using startTheater() method
      Theater.startTheater(builder);
      // add details to the Theater FlatBuffer
      Theater.addDriveIn(builder, driveIn);

      // mark end of data being entered in Greet FlatBuffer
      int theater = Theater.endTheater(builder);

      // finish the builder
      builder.finish(theater);

      // get the bytes to be stored
      byte[] data = builder.sizedByteArray();

      String filename = "theater_flatbuffers_output";
      System.out.println("Saving theater to file: " + filename);
      // write the builder content to the file named theater_flatbuffers_output
      try(FileOutputStream output = new FileOutputStream(filename)){
         output.write(data);
      }
      System.out.println("Saved theater with following data to disk: \n" + theater);
   }
}	

接下来,我们将有一个读取器 (reader)来读取theater信息:

TheaterReader.java

package com.tutorialspoint.theater;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.ByteBuffer;

public class TheaterReader {
   public static void main(String[] args) throws FileNotFoundException, IOException {

      String filename = "theater_flatbuffers_output";
      System.out.println("Reading from file " + filename);
      try(FileInputStream input = new FileInputStream(filename)) {
         // get the serialized data
         byte[] data = input.readAllBytes();
         ByteBuffer buf = ByteBuffer.wrap(data);
         // read the root object in serialized data
         Theater theater = Theater.getRootAsTheater(buf);
         // print theater values 
         System.out.println("Drive In: " + theater.driveIn());
      }
   }
}

编译项目

现在我们已经设置了读取器写入器,让我们编译项目。

mvn clean install

序列化 Java 对象

现在,编译后,让我们先执行写入器

java -cp .\target\flatbuffers-tutorial-1.0.jar com.tutorialspoint.theater.TheaterWriter

Saving theater to file: theater_flatbuffers_output
Saved theater with following data to disk:
8

反序列化已序列化的对象

现在,让我们执行读取器从同一个文件读取:

java -cp .\target\flatbuffers-tutorial-1.0.jar com.tutorialspoint.theater.TheaterReader

Reading from file theater_flatbuffers_output
Drive In: true

因此,正如我们所看到的,我们能够通过将二进制数据反序列化为Theater对象来读取序列化后的字符串。在下一章Flat Buffers - Enum中,我们将了解数字

FlatBuffers - 枚举 (enum)

概述

枚举 (enum)数据类型是 FlatBuffers 的复合数据类型之一。它相当于在我们使用的语言中的枚举 (enum),例如Java等。

继续我们来自Flat Buffers - String章节的theater示例,以下是我们需要使用的语法,用于指示 FlatBuffers 我们将创建一个枚举 (enum)

theater.fbs

namespace com.tutorialspoint.theater;

enum PAYMENT_SYSTEM: byte { CASH = 0, CREDIT_CARD = 1, DEBIT_CARD, APP = 3 }

table Theater {
   payment:PAYMENT_SYSTEM;
}
root_type Theater;

现在我们的包含一个枚举 (enum)属性。我们为每个枚举常量分配了一个值,除了 DEBIT_CARD,它默认取增量值 2。

我们定义了枚举 (enum),并在下面将其用作数据类型以及“payment”属性。

从 fbs 文件创建 Java 类

要使用 FlatBuffers,我们现在必须使用flatc二进制文件从这个“.fbs”文件创建所需的类。让我们看看如何做到这一点:

flatc  --java theater.fbs

这将在当前目录中的com > tutorialspoint > theater文件夹中创建一个 Theater.java 和 PAYMENT_SYSTEM 类。我们像在Flat Buffers - Schema章节中所做的那样,在我们的应用程序中使用此类。

使用从 fbs 文件创建的 Java 类

TheaterWriter.java

package com.tutorialspoint.theater;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import com.google.flatbuffers.FlatBufferBuilder;

public class TheaterWriter {
   public static void main(String[] args) throws FileNotFoundException, IOException {
      // create a flat buffer builder
      // it will be used to create Theater FlatBuffer
      FlatBufferBuilder builder = new FlatBufferBuilder(1024);

      // create theater FlatBuffers using startTheater() method
      Theater.startTheater(builder);
      // add details to the Theater FlatBuffer
      Theater.addPayment(builder, PAYMENT_SYSTEM.DEBIT_CARD);

      // mark end of data being entered in Greet FlatBuffer
      int theater = Theater.endTheater(builder);

      // finish the builder
      builder.finish(theater);

      // get the bytes to be stored
      byte[] data = builder.sizedByteArray();

      String filename = "theater_flatbuffers_output";
      System.out.println("Saving theater to file: " + filename);
      // write the builder content to the file named theater_flatbuffers_output
      try(FileOutputStream output = new FileOutputStream(filename)){
         output.write(data);
      }
      System.out.println("Saved theater with following data to disk: \n" + theater);
   }
}	

接下来,我们将有一个读取器 (reader)来读取theater信息:

TheaterReader.java

package com.tutorialspoint.theater;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.ByteBuffer;

public class TheaterReader {
   public static void main(String[] args) throws FileNotFoundException, IOException {

      String filename = "theater_flatbuffers_output";
      System.out.println("Reading from file " + filename);
      try(FileInputStream input = new FileInputStream(filename)) {
         // get the serialized data
         byte[] data = input.readAllBytes();
         ByteBuffer buf = ByteBuffer.wrap(data);
         // read the root object in serialized data
         Theater theater = Theater.getRootAsTheater(buf);
         // print theater values 
         System.out.println("Payment Method: " + theater.payment());
      }
   }
}

编译项目

现在我们已经设置了读取器写入器,让我们编译项目。

mvn clean install

序列化 Java 对象

现在,编译后,让我们先执行写入器 (writer)

> java -cp .\target\flatbuffers-tutorial-1.0.jar com.tutorialspoint.theater.TheaterWriter

Saving theater information to file: theater_flatbuffers_output
Saved theater information with following data to disk:
8

反序列化已序列化的对象

现在,让我们执行读取器从同一个文件读取:

java -cp .\target\flatbuffers-tutorial-1.0.jar com.tutorialspoint.theater.TheaterReader

Reading from file theater_flatbuffers_output
Payment Method: 2

因此,正如我们所看到的,我们能够通过将二进制数据反序列化为Theater对象来读取序列化后的枚举 (enum)。在下一章Protocol Buffers - Vector中,我们将了解向量,一种复合类型。

FlatBuffers - 向量

概述

向量 (Vector)数据类型是 FlatBuffers 的复合数据类型之一。它相当于在我们使用的语言中的数组 (array)列表 (List),例如Java等。

继续我们来自Flat Buffers - String章节的theater示例,以下是我们需要使用的语法,用于指示 FlatBuffers 我们将创建一个向量 (vector)

theater.fbs

namespace com.tutorialspoint.theater;

table Theater {
   snacks:[string];  // vector of strings
   tickets:[float];    // vector of floats 	
}
root_type Theater;

现在我们的包含字符串和浮点数的向量 (vector)属性。

从 fbs 文件创建 Java 类

要使用 FlatBuffers,我们现在必须使用flatc二进制文件从这个“.fbs”文件创建所需的类。让我们看看如何做到这一点:

flatc  --java theater.fbs

这将在当前目录中的com > tutorialspoint > theater文件夹中创建一个 Theater.java 类。我们像在Flat Buffers - Schema章节中所做的那样,在我们的应用程序中使用此类。

使用从 fbs 文件创建的 Java 类

创建和写入向量

为了创建一个向量,我们需要首先准备标量类型数组的偏移量,然后我们可以将向量添加到 flat buffer 中。

// create data for an array of strings
int popcorn = builder.createString("Popcorn");
int coke = builder.createString("Coke");
int chips = builder.createString("Chips");
int soda = builder.createString("Soda");

// create array for snacks
int[] snacks = {popcorn, coke, chips, soda};

// create offset for snacks vector
int snacksVector = Theater.createSnacksVector(builder, snacks);

// add details to the Theater FlatBuffer
Theater.addSnacks(builder, snacksVector);

以下示例代码展示了创建字符串和整数向量的过程。

TheaterWriter.java

package com.tutorialspoint.theater;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import com.google.flatbuffers.FlatBufferBuilder;

public class TheaterWriter {
   public static void main(String[] args) throws FileNotFoundException, IOException {
      // create a flat buffer builder
      // it will be used to create Theater FlatBuffer
      FlatBufferBuilder builder = new FlatBufferBuilder(1024);

      // create data for an array of strings
      int popcorn = builder.createString("Popcorn");
      int coke = builder.createString("Coke");
      int chips = builder.createString("Chips");
      int soda = builder.createString("Soda");
      
      // create array for snacks
      int[] snacks = {popcorn, coke, chips, soda};
      
      // create array for tickets
      float[] tickets = {100.0f, 100.f, 200.f};
      
      // create offset for snacks vector
      int snacksVector = Theater.createSnacksVector(builder, snacks);
      
      // create offset for tickets vector
      int ticketsVector = Theater.createTicketsVector(builder, tickets);
      
      // create theater FlatBuffers using startTheater() method
      Theater.startTheater(builder);
      // add details to the Theater FlatBuffer
      Theater.addSnacks(builder, snacksVector);
      Theater.addTickets(builder, ticketsVector);       

      // mark end of data being entered in Greet FlatBuffer
      int theater = Theater.endTheater(builder);

      // finish the builder
      builder.finish(theater);

      // get the bytes to be stored
      byte[] data = builder.sizedByteArray();

      String filename = "theater_flatbuffers_output";
      System.out.println("Saving theater to file: " + filename);
      // write the builder content to the file named theater_flatbuffers_output
      try(FileOutputStream output = new FileOutputStream(filename)){
         output.write(data);
      }
      System.out.println("Saved theater with following data to disk: \n" + theater);
   }
}	

读取向量

为了读取向量,我们有方法来获取向量的长度并通过索引获取条目,如下所示。

// iterate snacks vector of length determined by snacksLength() method
for(int i = 0; i < theater.snacksLength(); i++ ) {
   // get a snack by its index
   System.out.print(" " + theater.snacks(i));
}

以下示例代码展示了读取字符串和整数向量的过程。

TheaterReader.java

package com.tutorialspoint.theater;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.ByteBuffer;

public class TheaterReader {
   public static void main(String[] args) throws FileNotFoundException, IOException {

      String filename = "theater_flatbuffers_output";
      System.out.println("Reading from file " + filename);
      try(FileInputStream input = new FileInputStream(filename)) {
         // get the serialized data
         byte[] data = input.readAllBytes();
         ByteBuffer buf = ByteBuffer.wrap(data);
         // read the root object in serialized data
         Theater theater = Theater.getRootAsTheater(buf);
         // print theater values 
         System.out.println("Snacks: ");
         for(int i = 0; i < theater.snacksLength(); i++ ) {
            System.out.print(" " + theater.snacks(i));
         }
         System.out.println("\nTickets: ");
         for(int i = 0; i < theater.ticketsLength(); i++ ) {
            System.out.print(" " + theater.tickets(i));
         }         
      }
   }
}

编译项目

现在我们已经设置了读取器写入器,让我们编译项目。

mvn clean install

序列化 Java 对象

现在,编译后,让我们先执行写入器 (writer)

> java -cp .\target\flatbuffers-tutorial-1.0.jar com.tutorialspoint.theater.TheaterWriter

Saving theater information to file: theater_flatbuffers_output
Saved theater information with following data to disk:
96

反序列化已序列化的对象

现在,让我们执行读取器从同一个文件读取:

java -cp .\target\flatbuffers-tutorial-1.0.jar com.tutorialspoint.theater.TheaterReader

Reading from file theater_flatbuffers_output
Snacks:
 Popcorn Coke Chips Soda
Tickets:
 100.0 100.0 200.0

因此,正如我们所看到的,我们能够通过将二进制数据反序列化为Theater对象来读取序列化后的向量 (vector)。在下一章Flat Buffers - struct中,我们将了解结构体,一种复合类型。

FlatBuffers - 结构体 (struct)

概述

结构体 (struct)数据类型是 FlatBuffers 的复合数据类型之一。它用于创建不可变的数据结构。结构体占用更少的内存,查找速度很快。结构体通常是标量类型的组合。

继续我们来自Flat Buffers - String章节的theater示例,以下是我们需要使用的语法,用于指示 FlatBuffers 我们将创建一个结构体 (struct)

theater.fbs

namespace com.tutorialspoint.theater;

struct Position {
   x: int;
   y: int;
   z: int;
}
table Theater {
   location: Position;
}
root_type Theater;

现在我们的包含定义为 Position 类型的 location 属性。Position 是一个结构体,用于定义三个整数的数据结构。

从 fbs 文件创建 Java 类

要使用 FlatBuffers,我们现在必须使用flatc二进制文件从这个“.fbs”文件创建所需的类。让我们看看如何做到这一点:

flatc  --java theater.fbs

这将在当前目录中的com > tutorialspoint > theater文件夹中创建TheaterPosition类。我们像在Flat Buffers - Schema章节中所做的那样,在我们的应用程序中使用此类。

使用从 fbs 文件创建的 Java 类

创建和写入结构体

为了创建一个结构体,我们需要首先准备标量类型数组的偏移量,然后我们可以将向量添加到 flat buffer 中。

// create offset for location struct
int location = Position.createPosition(builder, 100, 110, 120);

// add details to the Theater FlatBuffer
Theater.addLocation(builder, location); 

以下示例代码展示了创建整数结构体的过程。

TheaterWriter.java

package com.tutorialspoint.theater;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import com.google.flatbuffers.FlatBufferBuilder;

public class TheaterWriter {
   public static void main(String[] args) throws FileNotFoundException, IOException {
      // create a flat buffer builder
      // it will be used to create Theater FlatBuffer
      FlatBufferBuilder builder = new FlatBufferBuilder(1024);

      // create offset for location struct
      int location = Position.createPosition(builder, 100, 110, 120);
      
      // create theater FlatBuffers using startTheater() method
      Theater.startTheater(builder);
      // add details to the Theater FlatBuffer
      Theater.addLocation(builder, location);      

      // mark end of data being entered in Greet FlatBuffer
      int theater = Theater.endTheater(builder);

      // finish the builder
      builder.finish(theater);

      // get the bytes to be stored
      byte[] data = builder.sizedByteArray();

      String filename = "theater_flatbuffers_output";
      System.out.println("Saving theater to file: " + filename);
      // write the builder content to the file named theater_flatbuffers_output
      try(FileOutputStream output = new FileOutputStream(filename)){
         output.write(data);
      }
      System.out.println("Saved theater with following data to disk: \n" + theater);
   }
}	

读取结构体

为了读取结构体,我们有方法来获取结构体的每个值。

Position position = theater.location();
System.out.println("x: " + position.x());
System.out.println("y: " + position.y());
System.out.println("z: " + position.z());

以下示例代码展示了读取整数结构体的过程。

TheaterReader.java

package com.tutorialspoint.theater;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.ByteBuffer;

public class TheaterReader {
   public static void main(String[] args) throws FileNotFoundException, IOException {

      String filename = "theater_flatbuffers_output";
      System.out.println("Reading from file " + filename);
      try(FileInputStream input = new FileInputStream(filename)) {
         // get the serialized data
         byte[] data = input.readAllBytes();
         ByteBuffer buf = ByteBuffer.wrap(data);
         // read the root object in serialized data
         Theater theater = Theater.getRootAsTheater(buf);
         // print theater values 
         System.out.println("Location: ");
         Position position = theater.location();
         System.out.println("x: " + position.x());
         System.out.println("y: " + position.y());
         System.out.println("z: " + position.z());        
      }
   }
}

编译项目

现在我们已经设置了读取器写入器,让我们编译项目。

mvn clean install

序列化 Java 对象

现在,编译后,让我们先执行写入器 (writer)

> java -cp .\target\flatbuffers-tutorial-1.0.jar com.tutorialspoint.theater.TheaterWriter

Saving theater information to file: theater_flatbuffers_output
Saved theater information with following data to disk:
16

反序列化已序列化的对象

现在,让我们执行读取器从同一个文件读取:

java -cp .\target\flatbuffers-tutorial-1.0.jar com.tutorialspoint.theater.TheaterReader

Reading from file theater_flatbuffers_output
Location:
x: 100
y: 110
z: 120

因此,正如我们所看到的,我们能够通过将二进制数据反序列化为Theater对象来读取序列化后的结构体 (struct)。在下一章Flat Buffers - union中,我们将了解联合体,一种复合类型。

FlatBuffers - 联合体 (union)

概述

联合体 (union)数据类型是 FlatBuffers 的复合数据类型之一。它用于创建灵活的数据结构,可以采用任何所需类型。

继续我们来自Flat Buffers - String章节的theater示例,以下是我们需要使用的语法,用于指示 FlatBuffers 我们将创建一个联合体 (union)

theater.fbs

namespace com.tutorialspoint.theater;

union People { Employee, Viewer }

table Theater {
   people: People;
}

table Employee {
   name:string;
   address:string;
   id: int;
}

table Viewer {
   name: string;
   address: string;
}
root_type Theater;

现在我们的包含定义为两个表 Employee 和 Viewer 的 People 属性。在 Theater 表中,我们定义了联合类型的 people,这意味着我们可以将 Employee 或 Viewer 中的任何一个存储在 people 变量中。

从 fbs 文件创建 Java 类

要使用 FlatBuffers,我们现在必须使用flatc二进制文件从这个“.fbs”文件创建所需的类。让我们看看如何做到这一点:

flatc  --java theater.fbs

这将在当前目录中的com > tutorialspoint > theater文件夹中创建TheaterPeopleEmployeeViewer类。我们像在Flat Buffers - Schema章节中所做的那样,在我们的应用程序中使用此类。

使用从 fbs 文件创建的 Java 类

创建和写入联合体

为了创建一个联合体,我们需要首先准备所需类型的偏移量,例如 Viewer,然后我们可以将 Viewer 与其类型一起添加到 flat buffer 中。

// create offset for Viewer
int viewerName = builder.createString("Mery");
int viewerAddress = builder.createString("Avenue 4");
int viewer = Viewer.createViewer(builder, viewerName, viewerAddress);

//add union tyoe
Theater.addPeopleType(builder, People.Viewer);
// add details to the Theater FlatBuffer
Theater.addPeople(builder, viewer);

以下示例代码展示了创建联合体的过程。

TheaterWriter.java

package com.tutorialspoint.theater;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import com.google.flatbuffers.FlatBufferBuilder;

public class TheaterWriter {
   public static void main(String[] args) throws FileNotFoundException, IOException {
      // create a flat buffer builder
      // it will be used to create Theater FlatBuffer
      FlatBufferBuilder builder = new FlatBufferBuilder(1024);
      
      // create offset for Viewer
      int viewerName = builder.createString("Mery");
      int viewerAddress = builder.createString("Avenue 4");
      int viewer = Viewer.createViewer(builder, viewerName, viewerAddress);
      
      // create offset for vector
      //int people = Theater.createPeople
      
      // create theater FlatBuffers using startTheater() method
      Theater.startTheater(builder);

      //add union type
      Theater.addPeopleType(builder, People.Viewer);

      // add details to the Theater FlatBuffer
      Theater.addPeople(builder, viewer);
      
      // mark end of data being entered in Greet FlatBuffer
      int theater = Theater.endTheater(builder);

      // finish the builder
      builder.finish(theater);

      // get the bytes to be stored
      byte[] data = builder.sizedByteArray();

      String filename = "theater_flatbuffers_output";
      System.out.println("Saving theater to file: " + filename);
      // write the builder content to the file named theater_flatbuffers_output
      try(FileOutputStream output = new FileOutputStream(filename)){
         output.write(data);
      }
      System.out.println("Saved theater with following data to disk: \n" + theater);
   }
}	

读取联合体

为了读取一个联合体(Union),我们可以检查联合体对象的类型,然后相应地检索值。

// get the saved union type
int unionType = theater.peopleType();

// if union is of type Viewer
if(unionType == People.Viewer) {
   Viewer viewer = (Viewer)theater.people(new Viewer());
   System.out.println("Name: " + viewer.name());
   System.out.println("Address: " + viewer.address());       	 
} 
// if union is of type Employee
else if(unionType == People.Employee) {
   Employee employee = (Employee)theater.people(new Employee());
   System.out.println("Name: " + employee.name());
   System.out.println("Address: " + employee.address());  
   System.out.println("Id: " + employee.id()); 
}

下面的示例代码展示了读取联合体的过程。

TheaterReader.java

package com.tutorialspoint.theater;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.ByteBuffer;

public class TheaterReader {
   public static void main(String[] args) throws FileNotFoundException, IOException {

      String filename = "theater_flatbuffers_output";
      System.out.println("Reading from file " + filename);
      try(FileInputStream input = new FileInputStream(filename)) {
         // get the serialized data
         byte[] data = input.readAllBytes();
         ByteBuffer buf = ByteBuffer.wrap(data);
         // read the root object in serialized data
         Theater theater = Theater.getRootAsTheater(buf);
         // print theater values 
         System.out.println("People: ");
         // get the type of union
		 int unionType = theater.peopleType();
         // if union is of Viewer type  
         if(unionType == People.Viewer) {
            Viewer viewer = (Viewer)theater.people(new Viewer());
            System.out.println("Name: " + viewer.name());
            System.out.println("Address: " + viewer.address());       	 
         } else if(unionType == People.Employee) {
            Employee employee = (Employee)theater.people(new Employee());
            System.out.println("Name: " + employee.name());
            System.out.println("Address: " + employee.address());  
            System.out.println("Id: " + employee.id()); 
         }       
      }
   }
}

编译项目

现在我们已经设置了读取器写入器,让我们编译项目。

mvn clean install

序列化 Java 对象

现在,编译后,让我们先执行写入器 (writer)

> java -cp .\target\flatbuffers-tutorial-1.0.jar com.tutorialspoint.theater.TheaterWriter

Saving theater information to file: theater_flatbuffers_output
Saved theater information with following data to disk:
60

反序列化已序列化的对象

现在,让我们执行读取器从同一个文件读取:

java -cp .\target\flatbuffers-tutorial-1.0.jar com.tutorialspoint.theater.TheaterReader

Reading from file theater_flatbuffers_output
People:
Name: Mery
Address: Avenue 4

因此,正如我们所看到的,我们能够通过将二进制数据反序列化为**Theater**对象来读取序列化的**struct**。在下一章Flat Buffers - 嵌套表中,我们将了解复合类型嵌套表。

FlatBuffers - 嵌套表

概述

在这里,我们将学习如何在 Flat Buffers 中创建嵌套表。它相当于一个嵌套的**Java**类。

继续我们从Flat Buffers - 字符串章节中的**theater**示例,以下是我们需要使用的语法,以便指示 FlatBuffers 我们将创建一个**嵌套表**:

theater.fbs

namespace com.tutorialspoint.theater;

table Theater {
   owner: TheaterOwner;
}

table TheaterOwner {
	name:string;
	address:string;
}
root_type Theater;

现在我们的**Theater**表包含一个嵌套表,即关于剧院所有者的信息。

从 fbs 文件创建 Java 类

要使用 FlatBuffers,我们现在必须使用flatc二进制文件从这个“.fbs”文件创建所需的类。让我们看看如何做到这一点:

flatc --java theater.fbs

这将在当前目录的**com > tutorialspoint > theater**文件夹中创建一个 Theater 和 TheaterOwner 类。我们在应用程序中使用此类,与Flat Buffers - 模式章节中所做的一样。

使用从 fbs 文件创建的 Java 类

TheaterWriter.java

package com.tutorialspoint.theater;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import com.google.flatbuffers.FlatBufferBuilder;

public class TheaterWriter {
   public static void main(String[] args) throws FileNotFoundException, IOException {
      // create a flat buffer builder
      // it will be used to create Theater FlatBuffer
      FlatBufferBuilder builder = new FlatBufferBuilder(1024);
      
      // create offset for TheaterOwner
      int ownerName = builder.createString("Mery");
      int ownerAddress = builder.createString("Avenue 4");
      int owner = TheaterOwner.createTheaterOwner(builder, ownerName, ownerAddress);
      
      // create theater FlatBuffers using startTheater() method
      Theater.startTheater(builder);
      // add details to the Theater FlatBuffer
      Theater.addOwner(builder, owner);      
      
      // mark end of data being entered in Greet FlatBuffer
      int theater = Theater.endTheater(builder);

      // finish the builder
      builder.finish(theater);

      // get the bytes to be stored
      byte[] data = builder.sizedByteArray();

      String filename = "theater_flatbuffers_output";
      System.out.println("Saving theater to file: " + filename);
      // write the builder content to the file named theater_flatbuffers_output
      try(FileOutputStream output = new FileOutputStream(filename)){
         output.write(data);
      }
      System.out.println("Saved theater with following data to disk: \n" + theater);
   }
}	

接下来,我们将有一个读取器 (reader)来读取theater信息:

TheaterReader.java

package com.tutorialspoint.theater;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.ByteBuffer;

public class TheaterReader {
   public static void main(String[] args) throws FileNotFoundException, IOException {

      String filename = "theater_flatbuffers_output";
      System.out.println("Reading from file " + filename);
      try(FileInputStream input = new FileInputStream(filename)) {
         // get the serialized data
         byte[] data = input.readAllBytes();
         ByteBuffer buf = ByteBuffer.wrap(data);
         // read the root object in serialized data
         Theater theater = Theater.getRootAsTheater(buf);
         // print theater values 
         System.out.println("Owner Details: ");
         TheaterOwner owner = theater.owner();
         System.out.println("Name: " + owner.name());
         System.out.println("Address: " + owner.address());        
      }
   }
}

编译项目

现在我们已经设置了读取器写入器,让我们编译项目。

mvn clean install

序列化 Java 对象

现在,编译后,让我们先执行写入器

java -cp .\target\flatbuffers-tutorial-1.0.jar com.tutorialspoint.theater.TheaterWriter

Saving theater to file: theater_flatbuffers_output
Saved theater with following data to disk:
56

反序列化已序列化的对象

现在,让我们执行读取器从同一个文件读取:

java -cp .\target\flatbuffers-tutorial-1.0.jar com.tutorialspoint.theater.TheaterReader

Reading from file theater_flatbuffers_output
Owner Details:
Name: Mery
Address: Avenue 4

因此,正如我们所看到的,我们能够通过将二进制数据反序列化为**Theater**对象来读取序列化的嵌套表/对象。

FlatBuffers - 默认值

概述

我们在之前的示例中已经看到了如何在 Flat Buffers 中序列化和反序列化各种类型。如果我们没有指定任何值,则会存储默认值。如果我们为变量指定相同的默认值,则 FlatBuffers 不会分配额外的空间。

Flat Buffers 支持其数据类型的默认值,如下表所示:

数据类型 默认值
int16 / short / int / long 0
Float/double 0.0
字符串 空字符串
布尔值 False
枚举 第一个枚举项,即“index=0”的项
向量 空列表
嵌套类 null

因此,如果用户没有为这些数据类型指定数据,则它们将采用上述默认值。现在,让我们继续我们的**theater**示例来演示它的工作原理。

在这个示例中,我们将让所有字段都使用默认值。唯一指定的字段将是剧院的名称。

继续我们从Flat Buffers - 字符串章节中的**theater**示例,以下是我们需要使用的语法,以便指示 FlatBuffers 我们将创建各种数据类型:

theater.fbs

namespace com.tutorialspoint.theater;

enum PAYMENT_SYSTEM: int { CASH = 0, CREDIT_CARD = 1, DEBIT_CARD, APP = 3 }

table Theater {
   name:string;
   address:string;
   
   total_capacity:short;
   mobile:int;
   base_ticket_price:float;
   
   drive_in:bool;
   
   payment:PAYMENT_SYSTEM;
   
   snacks:[string];
   
   owner: TheaterOwner;
}

table TheaterOwner {
	name:string;
	address:string;
}
root_type Theater;

现在我们的**Theater**表包含多个属性。

从 fbs 文件创建 Java 类

要使用 FlatBuffers,我们现在必须使用flatc二进制文件从这个“.fbs”文件创建所需的类。让我们看看如何做到这一点:

flatc --java theater.fbs

这将在当前目录的**com > tutorialspoint > theater**文件夹中创建一个 Theater、TheaterOwner 和 PAYMENT_SYSTEM 类。我们在应用程序中使用此类,与Flat Buffers - 模式章节中所做的一样。

使用从 fbs 文件创建的 Java 类

TheaterWriter.java

package com.tutorialspoint.theater;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import com.google.flatbuffers.FlatBufferBuilder;

public class TheaterWriter {
   public static void main(String[] args) throws FileNotFoundException, IOException {
      // create a flat buffer builder
      // it will be used to create Theater FlatBuffer
      FlatBufferBuilder builder = new FlatBufferBuilder(1024);
      
      // create offset for name
      int name = builder.createString("Mery");
      
      // create theater FlatBuffers using startTheater() method
      Theater.startTheater(builder);
      // add details to the Theater FlatBuffer
      Theater.addName(builder, name);      
      
      // mark end of data being entered in Greet FlatBuffer
      int theater = Theater.endTheater(builder);

      // finish the builder
      builder.finish(theater);

      // get the bytes to be stored
      byte[] data = builder.sizedByteArray();

      String filename = "theater_flatbuffers_output";
      System.out.println("Saving theater to file: " + filename);
      // write the builder content to the file named theater_flatbuffers_output
      try(FileOutputStream output = new FileOutputStream(filename)){
         output.write(data);
      }
      System.out.println("Saved theater with following data to disk: \n" + theater);
   }
}	

接下来,我们将有一个读取器 (reader)来读取theater信息:

TheaterReader.java

package com.tutorialspoint.theater;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.ByteBuffer;

public class TheaterReader {
   public static void main(String[] args) throws FileNotFoundException, IOException {

      String filename = "theater_flatbuffers_output";
      System.out.println("Reading from file " + filename);
      try(FileInputStream input = new FileInputStream(filename)) {
         // get the serialized data
         byte[] data = input.readAllBytes();
         ByteBuffer buf = ByteBuffer.wrap(data);
         // read the root object in serialized data
         Theater theater = Theater.getRootAsTheater(buf);

         // print theater values 
         System.out.println("Name: " + theater.name());
         System.out.println("Address: " + theater.address());
         System.out.println("Total Capacity: " + theater.totalCapacity());
         System.out.println("Mobile: " + theater.mobile());
         System.out.println("Base Ticket Price: " + theater.baseTicketPrice());
         System.out.println("Drive In: " + theater.driveIn());
         System.out.println("Snacks: ");
         if(theater.snacksLength() != 0) {
            for(int i = 0; i < theater.snacksLength(); i++ ) {
               System.out.print(" " + theater.snacks(i));
            } 
         }else {
            System.out.println("Snacks are empty.");
         }

         System.out.println("Payment Method: " + PAYMENT_SYSTEM.name(theater.payment()));        
         System.out.println("Owner Details: ");
         TheaterOwner owner = theater.owner();
         if(owner != null) {
            System.out.println("Name: " + owner.name());
            System.out.println("Address: " + owner.address());        	 
         }else {
            System.out.println("Owner " + owner);
         }        
      }
   }
}

编译项目

现在我们已经设置了读取器写入器,让我们编译项目。

mvn clean install

序列化 Java 对象

现在,编译后,让我们先执行写入器

java -cp .\target\flatbuffers-tutorial-1.0.jar com.tutorialspoint.theater.TheaterWriter

Saving theater to file: theater_flatbuffers_output
Saved theater with following data to disk:
20

反序列化已序列化的对象

现在,让我们执行读取器从同一个文件读取:

java -cp .\target\flatbuffers-tutorial-1.0.jar com.tutorialspoint.theater.TheaterReader

Reading from file theater_flatbuffers_output
Name: Mery
Address: null
Total Capacity: 0
Mobile: 0
Base Ticket Price: 0.0
Drive In: false
Snacks:
Snacks are empty.
Payment Method: CASH
Owner Details:
Owner null

因此,正如我们所看到的,我们能够通过将二进制数据反序列化为**Theater**对象来读取默认值。

FlatBuffers - JSON 转二进制

概述

JSON 是一种非常流行的网络数据传输格式。为了提供 JSON 兼容性,Flat Buffers 编译器 flatc 可以将源 JSON 转换为 Flat Buffer 二进制格式,然后可以使用该格式反序列化最初由 JSON 表示的对象。

考虑以下包含 Theater 对象信息的 JSON

theater.json

{
   "name" : "Silver Screener",
   "address" : "212, Maple Street, LA, California",
   "mobile": 12322224
}

theater.fbs

这是我们的 Flat Buffers 模式文件

namespace com.tutorialspoint.theater;

table Theater {
   name:string;
   address:string;
   mobile:int;
}
root_type Theater;

现在让我们首先使用以下命令获取 json(**theater.json**)的 Flat Buffer 二进制表示形式,根据我们的模式(**theater.fbs**):

flatc --binary theater.fbs theater.json

它将在当前文件夹中创建 theater.bin,我们可以读取它来反序列化 Theater 对象。

从 fbs 文件创建 Java 类

要使用 FlatBuffers,我们现在必须使用flatc二进制文件从这个“.fbs”文件创建所需的类。让我们看看如何做到这一点:

flatc  --java theater.fbs

这将在当前目录的**com > tutorialspoint > theater**文件夹中创建一个 Theater 类。我们在应用程序中使用此类,与Flat Buffers - 模式章节中所做的一样。

使用从 fbs 文件创建的 Java 类

TheaterReader.java

package com.tutorialspoint.theater;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.ByteBuffer;

public class TheaterReader {
   public static void main(String[] args) throws FileNotFoundException, IOException {

      String filename = "theater.bin";
      System.out.println("Reading from file " + filename);
      try(FileInputStream input = new FileInputStream(filename)) {
         // get the serialized data
         byte[] data = input.readAllBytes();
         ByteBuffer buf = ByteBuffer.wrap(data);
         // read the root object in serialized data
         Theater theater = Theater.getRootAsTheater(buf);
         // print theater values 
         System.out.println("Name: " + theater.name());
         System.out.println("Address: " + theater.address());
         System.out.println("Mobile: " + theater.mobile());        
      }
   }
}

编译项目

现在我们已经设置了读取器写入器,让我们编译项目。

mvn clean install

反序列化已序列化的对象

现在,让我们执行读取器从同一个文件读取:

java -cp .\target\flatbuffers-tutorial-1.0.jar com.tutorialspoint.theater.TheaterReader

Reading from file theater.bin
Name: Silver Screener
Address: 212, Maple Street, LA, California
Mobile: 12322224

因此,正如我们所看到的,我们能够通过将二进制数据反序列化为**Theater**对象来读取默认值。

FlatBuffers - 二进制转 JSON

概述

JSON 是一种非常流行的网络数据传输格式。为了提供 JSON 兼容性,Flat Buffers 编译器 flatc 可以将源 JSON 转换为 Flat Buffer 二进制格式,然后可以使用该格式反序列化最初由 JSON 表示的对象。我们在之前的章节Flat Buffers - JSON 转二进制中已经演练过这个过程。现在我们将执行反向操作,从 Flat Buffers 二进制文件中检索 JSON。

考虑在之前的章节Flat Buffers - JSON 转二进制中创建的 theater.bin 文件。

以下是 Flat Buffers 编译器正确解释二进制数据所需的模式。

theater.fbs

namespace com.tutorialspoint.theater;

table Theater {
   name:string;
   address:string;
   mobile:int;
}
root_type Theater;

生成 JSON

现在让我们首先使用以下命令从我们的二进制文件(**theater.bin**)获取所需的 json(**theater.json**):

flatc --json --raw-binary theater.fbs -- theater.bin

它将在当前文件夹中创建如下所示的 theater.json。

{
   name: "Silver Screener",
   address: "212, Maple Street, LA, California",
   mobile: 12322224
}

严格模式

flatc 生成最小的 json。如果我们需要使用其他工具处理 JSON 并需要正确的带引号的标识符,则可以使用**--strict-json**,如下所示

flatc --json --raw-binary theater.fbs -- theater.bin --strict-json

它将在当前文件夹中创建如下所示的 theater.json。

{
   "name": "Silver Screener",
   "address": "212, Maple Street, LA, California",
   "mobile": 12322224
}

默认值

默认情况下,flatc 编译器会忽略默认值,并且默认值不会存储在二进制表示中。因此,这些值也不会出现在 JSON 中。为了实现这一点,我们可以使用**--defaults-json**选项,如下例所示。

让我们将 mobile 值保留为 json 中的默认值。

theater.json

{
   "name" : "Silver Screener",
   "address" : "212, Maple Street, LA, California",
   "mobile": 0
}

现在让我们首先使用以下命令获取 json(**theater.json**)的 Flat Buffer 二进制表示形式,根据我们的模式(**theater.fbs**):

flatc --binary theater.fbs theater.json

生成不包含默认值的 JSON

现在让我们首先使用以下命令从我们的二进制文件(**theater.bin**)获取所需的 json(**theater.json**):

flatc --json --raw-binary theater.fbs -- theater.bin

它将在当前文件夹中创建如下所示的 theater.json。

{
   name: "Silver Screener",
   address: "212, Maple Street, LA, California"
}

生成包含默认值的 JSON

现在使用**--defaults-json**选项生成 JSON。

flatc --json --raw-binary theater.fbs -- theater.bin --defaults-json

它将在当前文件夹中创建如下所示的 theater.json。

{
   name: "Silver Screener",
   address: "212, Maple Street, LA, California",
   mobile: 0
}

Flat Buffers - 可变缓冲区

概述

每当我们创建一个 Flat Buffers 文件时,从那时起它就是只读的。我们可以使用 flatc 提供的具有常量访问器的类来读取此文件。这有助于在多个读取器中使用 Flat Buffer 文件时保持一致性。但有时,我们可能需要在读取后修改一个值,并需要将修改后的值传递给下一个读取器。我们可以通过从头开始创建一个新的 Flat Buffers 来实现这一点,这对于大型更改来说更好,更高效。对于小型更改,Flat Buffers 提供了一个选项**--gen-mutable**到**flatc**编译器

以生成非常量访问器来修改 FlatBuffers 文件,如下所示

flatc --java --gen-mutable theater.fbs

示例

考虑以下模式。

theater.fbs

namespace com.tutorialspoint.theater;

table Theater {
   name:string;
   address:string;
   int mobile;
}
root_type Theater;

从 fbs 文件创建 Java 类

要使用 Flat Buffers,我们现在将使用可变模式下的**flatc**编译器从这个“.fbs”文件创建所需的类。让我们看看如何操作:

flatc  --java --gen-mutable theater.fbs

这将在当前目录中的com > tutorialspoint > theater文件夹中创建一个 Theater.java 类。我们像在Flat Buffers - Schema章节中所做的那样,在我们的应用程序中使用此类。

使用从 fbs 文件创建的 Java 类

首先,让我们创建一个写入器 (writer)来写入theater信息:

TheaterWriter.java

package com.tutorialspoint.theater;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import com.google.flatbuffers.FlatBufferBuilder;

public class TheaterWriter {
   public static void main(String[] args) throws FileNotFoundException, IOException {
      // create a flat buffer builder
      // it will be used to create Theater FlatBuffer
      FlatBufferBuilder builder = new FlatBufferBuilder(1024);

      // create offset for name and address
      int name = builder.createString("Silver Screener");
      int address = builder.createString("212, Maple Street, LA, California");
      
      // create theater FlatBuffers using startTheater() method
      Theater.startTheater(builder);
      // add details to the Theater FlatBuffer
      Theater.addName(builder, name);   
      Theater.addAddress(builder, address);
      Theater.addMobile(builder, 12233345);

      // mark end of data being entered in Greet FlatBuffer
      int theater = Theater.endTheater(builder);

      // finish the builder
      builder.finish(theater);

      // get the bytes to be stored
      byte[] data = builder.sizedByteArray();

      String filename = "theater_flatbuffers_output";
      System.out.println("Saving theater to file: " + filename);
      // write the builder content to the file named theater_flatbuffers_output
      try(FileOutputStream output = new FileOutputStream(filename)){
         output.write(data);
      }
      System.out.println("Saved theater with following data to disk: \n" + theater);
   }
}	

接下来,我们将有一个读取器 (reader)来读取theater信息:

TheaterReader.java

package com.tutorialspoint.theater;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.ByteBuffer;

public class TheaterReader {
   public static void main(String[] args) throws FileNotFoundException, IOException {

      String filename = "theater_flatbuffers_output";
      System.out.println("Reading from file " + filename);
      try(FileInputStream input = new FileInputStream(filename)) {
         // get the serialized data
         byte[] data = input.readAllBytes();
         ByteBuffer buf = ByteBuffer.wrap(data);
         // read the root object in serialized data
         Theater theater = Theater.getRootAsTheater(buf);
         // print theater values 
         System.out.println("Name: " + theater.name());
         System.out.println("Address: " + theater.address());
         System.out.println("Mobile: " + theater.mobile());
         
         
         // Update mobile
         theater.mutateMobile(22333341);
         
         // we can write the theater object again to send it further
         // read the updated mobile value
         System.out.println("Updated Mobile: " + theater.mobile());
      }
   }
}

编译项目

现在我们已经设置了读取器写入器,让我们编译项目。

mvn clean install

序列化 Java 对象

现在,编译后,让我们先执行写入器

java -cp .\target\flatbuffers-tutorial-1.0.jar com.tutorialspoint.theater.TheaterWriter

Saving theater to file: theater_flatbuffers_output
Saved theater with following data to disk:
76

反序列化已序列化的对象

现在,让我们执行读取器从同一个文件读取:

java -cp .\target\flatbuffers-tutorial-1.0.jar com.tutorialspoint.theater.TheaterReader

Reading from file theater_flatbuffers_output
Name: Silver Screener
Address: 212, Maple Street, LA, California
Mobile: 12233345
Updated Mobile: 22333341

FlatBuffers - 语言无关性

概述

到目前为止,我们一直在使用 Java 来序列化和反序列化电影院数据。但是,Google Flat Buffers 提供的一个关键特性是**“语言无关性”**。在本节中,我们将学习如何使用 Java 序列化,并使用 Python 反序列化。

继续我们从Flat Buffers - 字符串章节中的**theater**示例,以下是我们在本例中使用的模式:

theater.fbs

namespace com.tutorialspoint.theater;

table Theater {
   name:string;
   address:string;
}
root_type Theater;

使用 Java 序列化

要使用 FlatBuffers,我们现在必须使用flatc二进制文件从这个“.fbs”文件创建所需的类。让我们看看如何做到这一点:

flatc --java theater.fbs

这将在当前目录中的com > tutorialspoint > theater文件夹中创建一个 Theater.java 类。我们像在Flat Buffers - Schema章节中所做的那样,在我们的应用程序中使用此类。

使用从 fbs 文件创建的 Java 类

首先,让我们创建一个写入器 (writer)来写入theater信息:

TheaterWriter.java

package com.tutorialspoint.theater;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import com.google.flatbuffers.FlatBufferBuilder;

public class TheaterWriter {
   public static void main(String[] args) throws FileNotFoundException, IOException {
      // create a flat buffer builder
      // it will be used to create Theater FlatBuffer
      FlatBufferBuilder builder = new FlatBufferBuilder(1024);

      int name = builder.createString("Silver Screener");
      int address = builder.createString("212, Maple Street, LA, California");

      // create theater FlatBuffers using startTheater() method
      Theater.startTheater(builder);
      // add the name and address to the Theater FlatBuffer
      Theater.addName(builder, name);
      Theater.addAddress(builder, address);

      // mark end of data being entered in Greet FlatBuffer
      int theater = Theater.endTheater(builder);

      // finish the builder
      builder.finish(theater);

      // get the bytes to be stored
      byte[] data = builder.sizedByteArray();

      String filename = "theater_flatbuffers_output";
      System.out.println("Saving theater to file: " + filename);
      // write the builder content to the file named theater_flatbuffers_output
      try(FileOutputStream output = new FileOutputStream(filename)){
         output.write(data);
      }
      System.out.println("Saved theater with following data to disk: \n" + theater);
   }
}	

编译项目

现在我们已经设置了读取器写入器,让我们编译项目。

mvn clean install

序列化 Java 对象

现在,编译后,让我们先执行写入器

java -cp .\target\flatbuffers-tutorial-1.0.jar com.tutorialspoint.theater.TheaterWriter

Saving theater to file: theater_flatbuffers_output
Saved theater with following data to disk:
72

使用 Python 反序列化序列化对象

从 proto 文件生成 Python 类

让我们为 Theater 类生成 Python 代码:

flatc  --python theater.fbs

执行此命令后,您会在当前目录的**com > tutorialspoint > theater**文件夹中看到一个自动生成的类**Theater.py**。此类将帮助我们反序列化**Theater**对象。

使用生成的 Python 类

现在,让我们**编写**数据读取器,它将使用 Java 读取包含序列化对象的文件:

theaterReader.py

import Theater

filename = "E:/theater_flatbuffers_output";
print("Reading from file: " + filename)

theater = Theater.Theater()

f = open(filename, "rb")
buf = f.read()
buf = bytearray(buf)
theater = theater.GetRootAs(buf);
f.close()

print("Name: " + theater.Name().decode("utf-8"))
print("Address: " + theater.Address().decode("utf-8"))

然后,让我们执行**读取器**。

py theaterReader.py

Reading from file: E:/theater_flatbuffers_output
Name: Silver Screener
Address: 212, Maple Street, LA, California

因此,正如我们所看到的,Java 客户端写入的所有值都被正确地反序列化并由我们的 Python 客户端读取,这有效地意味着 Flat Buffers 是语言无关的。

FlatBuffers - 向后兼容性

概述

FlatBuffers 模式是向后兼容的。这意味着,如果我们稍后更改、添加或删除 FlatBuffers 模式的属性,现有的代码仍然可以工作。这在维护遗留代码库时非常有用。考虑一种情况,其中 Theater 模式仅包含名称和地址,如下所示

theater.fbs

namespace com.tutorialspoint.theater;

table Theater {
   name:string;
   address:string;
}
root_type Theater;

如果我们为此模式生成代码,它将支持在 FlatBuffer bin 文件中存储名称和地址。

现在随着时间的推移,我们需要向模式添加一个手机号码,然后我们需要再次生成更新的代码。结果,我们还需要更新写入器和读取器代码。但在生产环境中,通常直接更改代码并不容易,并且进行此类更改可能会破坏整个系统。Flat Buffers 在这里确保旧的读取器代码仍然可以与新的模式生成的 FlatBuffers bin 文件一起正常工作,无需更改。

从 fbs 文件创建 Java 类

要使用 FlatBuffers,我们现在必须使用flatc二进制文件从这个“.fbs”文件创建所需的类。让我们看看如何做到这一点:

flatc  --java theater.fbs

这将在当前目录中的com > tutorialspoint > theater文件夹中创建一个 Theater.java 类。我们像在Flat Buffers - Schema章节中所做的那样,在我们的应用程序中使用此类。

使用从 fbs 文件创建的 Java 类

首先,让我们创建一个写入器 (writer)来写入theater信息:

TheaterWriter.java

package com.tutorialspoint.theater;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import com.google.flatbuffers.FlatBufferBuilder;

public class TheaterWriter {
   public static void main(String[] args) throws FileNotFoundException, IOException {
      // create a flat buffer builder
      // it will be used to create Theater FlatBuffer
      FlatBufferBuilder builder = new FlatBufferBuilder(1024);

      int name = builder.createString("Silver Screener");
      int address = builder.createString("212, Maple Street, LA, California");

      // create theater FlatBuffers using startTheater() method
      Theater.startTheater(builder);
      // add the name and address to the Theater FlatBuffer
      Theater.addName(builder, name);
      Theater.addAddress(builder, address);

      // mark end of data being entered in Greet FlatBuffer
      int theater = Theater.endTheater(builder);

      // finish the builder
      builder.finish(theater);

      // get the bytes to be stored
      byte[] data = builder.sizedByteArray();

      String filename = "theater_flatbuffers_output";
      System.out.println("Saving theater to file: " + filename);
      // write the builder content to the file named theater_flatbuffers_output
      try(FileOutputStream output = new FileOutputStream(filename)){
         output.write(data);
      }
      System.out.println("Saved theater with following data to disk: \n" + theater);
   }
}	

接下来,我们将有一个读取器 (reader)来读取theater信息:

TheaterReader.java

package com.tutorialspoint.theater;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.ByteBuffer;

public class TheaterReader {
   public static void main(String[] args) throws FileNotFoundException, IOException {

      String filename = "theater_flatbuffers_output";
      System.out.println("Reading from file " + filename);
      try(FileInputStream input = new FileInputStream(filename)) {
         // get the serialized data
         byte[] data = input.readAllBytes();
         ByteBuffer buf = ByteBuffer.wrap(data);
         // read the root object in serialized data
         Theater theater = Theater.getRootAsTheater(buf);
         // print theater values 
         
         System.out.println("Name: " + theater.name());
         System.out.println("Address: " + theater.address());
      }
   }
}

编译项目

现在我们已经设置了读取器写入器,让我们编译项目。

mvn clean install

序列化 Java 对象

现在,编译后,让我们先执行写入器

java -cp .\target\flatbuffers-tutorial-1.0.jar com.tutorialspoint.theater.TheaterWriter

Saving theater to file: theater_flatbuffers_output
Saved theater with following data to disk:
72

反序列化已序列化的对象

现在,让我们执行读取器从同一个文件读取:

java -cp .\target\flatbuffers-tutorial-1.0.jar com.tutorialspoint.theater.TheaterReader

Reading from file theater_flatbuffers_output
Name: Silver Screener
Address: 212, Maple Street, LA, California

向后兼容性测试

现在让我们向模式添加一个手机号码,更新写入器并运行读取器(无需更新它)以检查向后兼容性。

theater.fbs

namespace com.tutorialspoint.theater;

table Theater {
   name:string;
   address:string;
   mobile:int;
}
root_type Theater;

从 fbs 文件创建 Java 类

使用**flatc**二进制文件从此“.fbs”文件创建所需的类。

flatc  --java theater.fbs

使用从 fbs 文件创建的 Java 类

首先,让我们创建一个写入器 (writer)来写入theater信息:

TheaterWriter.java

package com.tutorialspoint.theater;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import com.google.flatbuffers.FlatBufferBuilder;

public class TheaterWriter {
   public static void main(String[] args) throws FileNotFoundException, IOException {
      // create a flat buffer builder
      // it will be used to create Theater FlatBuffer
      FlatBufferBuilder builder = new FlatBufferBuilder(1024);

      int name = builder.createString("Silver Screener");
      int address = builder.createString("212, Maple Street, LA, California");

      // create theater FlatBuffers using startTheater() method
      Theater.startTheater(builder);
      // add the name, address and mobile to the Theater FlatBuffer
      Theater.addName(builder, name);
      Theater.addAddress(builder, address);
      Theater.addMobile(builder, 12233345);

      // mark end of data being entered in Greet FlatBuffer
      int theater = Theater.endTheater(builder);

      // finish the builder
      builder.finish(theater);

      // get the bytes to be stored
      byte[] data = builder.sizedByteArray();

      String filename = "theater_flatbuffers_output";
      System.out.println("Saving theater to file: " + filename);
      // write the builder content to the file named theater_flatbuffers_output
      try(FileOutputStream output = new FileOutputStream(filename)){
         output.write(data);
      }
      System.out.println("Saved theater with following data to disk: \n" + theater);
   }
}	

编译项目

现在我们已经设置了**写入器**,让我们编译项目。

mvn clean install

序列化 Java 对象

现在,编译后,让我们先执行写入器

java -cp .\target\flatbuffers-tutorial-1.0.jar com.tutorialspoint.theater.TheaterWriter

Saving theater to file: theater_flatbuffers_output
Saved theater with following data to disk:
76

使用旧读取器反序列化序列化对象

现在,让我们执行读取器从同一个文件读取:

java -cp .\target\flatbuffers-tutorial-1.0.jar com.tutorialspoint.theater.TheaterReader

Reading from file theater_flatbuffers_output
Name: Silver Screener
Address: 212, Maple Street, LA, California

更新读取器并再次反序列化

TheaterReader.java

package com.tutorialspoint.theater;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.ByteBuffer;

public class TheaterReader {
   public static void main(String[] args) throws FileNotFoundException, IOException {

      String filename = "theater_flatbuffers_output";
      System.out.println("Reading from file " + filename);
      try(FileInputStream input = new FileInputStream(filename)) {
         // get the serialized data
         byte[] data = input.readAllBytes();
         ByteBuffer buf = ByteBuffer.wrap(data);
         // read the root object in serialized data
         Theater theater = Theater.getRootAsTheater(buf);
         // print theater values 
         
         System.out.println("Name: " + theater.name());
         System.out.println("Address: " + theater.address());
         System.out.println("Mobile: " + theater.mobile());
      }
   }
}

编译项目

现在我们已经设置了读取器写入器,让我们编译项目。

mvn clean install

反序列化已序列化的对象

现在,让我们执行读取器从同一个文件读取:

java -cp .\target\flatbuffers-tutorial-1.0.jar com.tutorialspoint.theater.TheaterReader

Reading from file theater_flatbuffers_output
Name: Silver Screener
Address: 212, Maple Street, LA, California
Mobile: 12233345
广告