Flat Buffers - 快速指南

Flat Buffers - 简介

在介绍Flat Buffers之前,让我们先简单了解一下序列化的背景,这就是Flat Buffers的作用。

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

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

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

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

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

为什么是Flat Buffers?

Google Flat Buffers 将对象序列化和反序列化为可以通过网络传输的字节。但是,还有一些其他库和机制可以传输数据。

那么,Flat Buffers 有什么特别之处?以下是它的一些重要功能 −

  • 语言独立 − Flat Buffers 编译器可以为许多语言创建代码,如 Java、Python、Go、C、C++ 等。因此,Java 对象可以从 Java 程序序列化为字节,并可以反序列化为 Python 对象,反之亦然。

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

  • 向后和向前兼容性 −Flat Buffers架构既向后兼容,又向前兼容。Flat Buffers的架构支持在较新的代码中添加更改,并允许弃用较旧的更改而不会破坏向后兼容性。

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

  • JSON 可转换 Flat buffers 模式文件可以转换为 JSON 文件,同样,我们可以使用 flat buffers 模式转换 JSON 文件。

Flat Buffers 与其他(XML/JSON/Java 序列化)

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

功能 Flat Buffers JSON XML
与语言无关
序列化数据大小 三者中最小 小于 XML 三者中最高
人类可读性 否,因为它使用单独的编码模式 是,因为它使用基于文本的格式 是,因为它使用基于文本的格式
序列化速度 三者中速度最快 比...快XML 三者中最慢
数据类型支持 比其他两个更丰富。支持复杂的数据类型,如 Any、one of 等。 支持基本数据类型 支持基本数据类型
支持不断发展的架构

Flat Buffers - 架构

概述

现在让我们使用 Google Flat Buffers,看看它如何与简单的 Greeting 应用程序配合使用。在这个例子中,我们将创建一个简单的应用程序,它将执行以下操作 −

问候编写器

  • 从用户那里获取问候语和用户名

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

问候阅读器

  • 读取我们存储在上述文件中的相同文件

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

Flat Buffers模式文件

Flat Buffers"模式文件"包含我们要序列化的数据的模式定义。数据存储在扩展名为 ".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 告知 flat buffers 编译器根表是 Greet,在生成代码时将作为主类。

Flat Buffers 代码生成

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

根据操作系统选择正确的二进制文件。我们将在 Windows 上安装 flat buffers 编译器二进制文件,但对于 Linux,步骤没有太大不同。

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

验证 Flat Buffers 编译器设置

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

flatc --version

flatc version 24.3.25

它确认 Flatc 已正确安装。现在让我们转到 创建 上面描述的 Java 问候应用程序。

Java 中的问候应用程序

现在我们已经安装了 flatc,我们可以使用 flatc 从 fa 文件自动生成代码。让我们先创建一个 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 > 下有一个自动生成的类当前目录中的问候 文件夹。

  • 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 {
        // 创建一个Flat Buffers构建器
        // 它将用于创建 Greet FlatBuffer
        FlatBufferBuilder builder = new FlatBufferBuilder(1024);
        
        // 从控制台读取问候语和用户名
        int Greeting = builder.createString(args[0]);
        int username = builder.createString(args[1]);
        
        // 使用 startGreet() 方法创建 Greet FlatBuffers
        Greet.startGreet(builder);
        // 将问候语和用户名添加到 Greet FlatBuffer 中
        Greet.addGreeting(builder, greeting);
        Greet.addUsername(builder, username);
        
        // 标记在 Gret FlatBuffer 中输入数据的结束
        int greet = Greet.endGreet(builder);
        
        // 完成构建器
        builder.finish(greet);
        
        // 获取要存储的字节
        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: 
" + greeting);
   }   
}

writer 仅接受 CLI 参数,创建 Greet 对象,对其进行序列化,然后将其转储到文件中。

现在让我们编写一个 reader 来读取文件 −

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)) {
         // 获取序列化数据
         byte[] data = input.readAllBytes();
         ByteBuffer buf = ByteBuffer.wrap(data);
         // 读取序列化数据中的根对象
         Greet greet = Greet.getRootAsGreet(buf);

         // 打印 greet 值
         System.out.println("Greeting: " + greet.greeting() + "
" + "Username: " + greet.username());
      }
   }
}

reader 只是从同一个文件中读取数据,对其进行反序列化,然后打印有关问候语的数据。

编译项目

现在我们已经设置了 readerwriter,让我们编译项目。

mvn clean install

序列化 Java 对象

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

java -cp .	arget\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 .	arget\flatbuffers-tutorial-1.0.jar com.tutorialspoint.greeting.GreetReader

Reading from file greeting_protobuf_output
Greeting: Hello
Username: John

因此,当我们看到由 writer 序列化并保存到文件的数据时,该确切数据已由 reader 正确反序列化并相应地打印。

Flat Buffers - 构造

概述

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

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

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

数据类型

  • table − "table" 是 Fl​​at Buffers 的一个非常基本的构建块。这在我们使用的语言中转换为类,例如 Java、Python 等

  • string − "string" 数据类型在我们使用的语言中转换为字符串,例如 Java、Python 等

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

  • bool − "bool" 数据类型是 Flat Buffers 的基本构建块之一。它在我们使用的语言中转换为布尔值,例如 Java、Python 等。

  • 枚举 − "枚举"是 Flat Buffers 的复合数据类型之一。它在我们使用的语言中转换为枚举,例如 Java。

  • 向量 − [] 表示法用于创建向量或数组,是 Flat Buffers 的复合数据类型之一。Flat Buffers 向量类似于 java 数组。

  • 结构 − "结构"是 Flat Buffers 的复合数据类型之一。它用于创建不可修改的标量值集。结构使用更少的内存并且查找速度非常快。

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

  • union − "union"用于创建可以接受任何不同类型值的结构。

Flat Buffers - table

概述

Flat Buffers 的最基本构建块是 table 属性。这相当于我们使用的语言中的 class,例如 Java、Python 等。

示例代码

以下是我们需要的语法,用于指示 Flat Buffers 我们将创建给定表的实例−

namespace com.tutorialspoint.theater;

table Theater {
}
root_type Theater;

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

解释

namespace com.tutorialspoint.theater;

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

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

table Theater

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

使用多个表属性

单个 fbs 文件也可以有多个表。例如,如果我们愿意,我们可以在同一个文件中添加 Visitor 表。Flat Buffers 将确保 Theater 类使用 root_type 属性保持主类。例如 −

namespace com.tutorialspoint.theater;

table Theater {
}

table Visitor {
}
root_type Theater;

从 fbs 文件创建 Java 类

要使用 Flat Buffers,我们现在必须使用 flat 二进制文件从此".fbs"文件创建所需的类。让我们看看如何做到这一点 −

flat --java theater.fbs

使用从 fbs 文件创建的 Java 类

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

// 使用默认缓冲区创建 FlatBuffer Builder
FlatBufferBuilder builder = new FlatBufferBuilder(1024);

// 使用 startTheater() 方法创建Theater  FlatBuffers
Theater.startTheater(builder);

在此阶段,它不是很有用,因为我们没有向表中添加任何属性。让我们在Flat Buffers - string一章中查看字符串时这样做。

Flat Buffers - string

概述

Flat Buffers 字符串会转换为我们使用的语言中的字符串,例如 Java、Python 等。继续theater示例,以下是我们需要指示 Flat Buffers 我们将创建字符串的语法 −

theater.fbs

namespace com.tutorialspoint.theater;

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

现在我们的 table 包含两个 string 属性。每个属性的默认值为 null。

从 fbs 文件创建 Java 类

要使用 Flat Buffers,我们现在必须使用 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 {
      // 创建一个Flat Buffers构建器
      // 它将用于创建Theater  FlatBuffer
      FlatBufferBuilder builder = new FlatBufferBuilder(1024);

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

      // 使用 startTheater() 方法创建Theater  FlatBuffers
      Theater.startTheater(builder);
      // add the name and address to the Theater FlatBuffer
      Theater.addName(builder, name);
      Theater.addAddress(builder, address);

      // 标记在 Gret FlatBuffer 中输入数据的结束
      int theater = Theater.endTheater(builder);

      // 完成构建器
      builder.finish(theater);

      // 获取要存储的字节
      byte[] data = builder.sizedByteArray();

      String filename = "theater_flatbuffers_output";
      System.out.println("Saving theater to file: " + filename);
      // 将构建器内容写入名为 theater_flatbuffers_output 的文件
      try(FileOutputStream output = new FileOutputStream(filename)){
         output.write(data);
      }
      System.out.println("Saved theater with following data to disk: 
" + theater);
   }
}	

接下来,我们将有一个阅读器来读取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)) {
         // 获取序列化数据
         byte[] data = input.readAllBytes();
         ByteBuffer buf = ByteBuffer.wrap(data);
         // 读取序列化数据中的根对象
         Theater theater = Theater.getRootAsTheater(buf);
         // 打印 theater 剧场值
         System.out.println("Name: " + theater.name() + "
" + "Address: " + theater.address());
      }
   }
}

编译项目

现在我们已经设置了readerwriter,让我们编译项目。

mvn clean install

序列化 Java 对象

现在,编译后,让我们先执行writer

java -cp .	arget\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 .	arget\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 中查看 numbers

Flat Buffers - Numbers

概述

Numbers 包括 flatbuffers 类型,如 int、short、float、double,它们是 Flat Buffers 的基本构建块。在我们所使用的语言(例如 Java、Python 等)中,它分别转换为 int、short float、double

继续使用 Flat Buffers - String 一章中的 theater 示例,以下是我们需要用来指示 Flat Buffers 创建 数字 的语法−

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 类

要使用 Flat Buffers,我们现在必须使用 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 {
      // 创建一个Flat Buffers构建器
      // 它将用于创建Theater  FlatBuffer
      FlatBufferBuilder builder = new FlatBufferBuilder(1024);

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

      // 使用 startTheater() 方法创建Theater  FlatBuffers
      Theater.startTheater(builder);
      // 向Theater  FlatBuffer 添加详细信息
      Theater.addTotalCapcity(builder, totalCapacity);
      Theater.addMobile(builder, mobile);
      Theater.addBaseTicketPrice(builder, baseTicketPrice);

      // 标记在 Gret FlatBuffer 中输入数据的结束
      int theater = Theater.endTheater(builder);

      // 完成构建器
      builder.finish(theater);

      // 获取要存储的字节
      byte[] data = builder.sizedByteArray();

      String filename = "theater_flatbuffers_output";
      System.out.println("Saving theater to file: " + filename);
      // 将构建器内容写入名为 theater_flatbuffers_output 的文件
      try(FileOutputStream output = new FileOutputStream(filename)){
         output.write(data);
      }
      System.out.println("Saved theater with following data to disk: 
" + theater);
   }
}	

接下来,我们将有一个阅读器来读取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)) {
         // 获取序列化数据
         byte[] data = input.readAllBytes();
         ByteBuffer buf = ByteBuffer.wrap(data);
         // 读取序列化数据中的根对象
         Theater theater = Theater.getRootAsTheater(buf);
         // 打印 theater 剧场值
         System.out.println("Total Capacity: " + theater.totalCapcity() 
            + "
" + "Mobile: " + theater.mobile()
            + "
" + "Base Ticket Price: " + theater.baseTicketPrice());
      }
   }
}

编译项目

现在我们已经设置了readerwriter,让我们编译项目。

mvn clean install

序列化 Java 对象

现在,编译后,让我们先执行writer

java -cp .	arget\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 .	arget\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 中查看 数字

Flat Buffers - Boolean

概述

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

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

theater.fbs

namespace com.tutorialspoint.theater;

table Theater {
   drive_in:bool;
}
root_type Theater;

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

从 FBS 文件创建 Java 类

要使用 Flat Buffers,我们现在必须使用 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 {
      // 创建一个Flat Buffers构建器
      // 它将用于创建Theater  FlatBuffer
      FlatBufferBuilder builder = new FlatBufferBuilder(1024);

      boolean driveIn = true; 

      // 使用 startTheater() 方法创建Theater  FlatBuffers
      Theater.startTheater(builder);
      // 向Theater  FlatBuffer 添加详细信息
      Theater.addDriveIn(builder, driveIn);

      // 标记在 Gret FlatBuffer 中输入数据的结束
      int theater = Theater.endTheater(builder);

      // 完成构建器
      builder.finish(theater);

      // 获取要存储的字节
      byte[] data = builder.sizedByteArray();

      String filename = "theater_flatbuffers_output";
      System.out.println("Saving theater to file: " + filename);
      // 将构建器内容写入名为 theater_flatbuffers_output 的文件
      try(FileOutputStream output = new FileOutputStream(filename)){
         output.write(data);
      }
      System.out.println("Saved theater with following data to disk: 
" + theater);
   }
}	

接下来,我们将有一个阅读器来读取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)) {
         // 获取序列化数据
         byte[] data = input.readAllBytes();
         ByteBuffer buf = ByteBuffer.wrap(data);
         // 读取序列化数据中的根对象
         Theater theater = Theater.getRootAsTheater(buf);
         // 打印 theater 剧场值
         System.out.println("Drive In: " + theater.driveIn());
      }
   }
}

编译项目

现在我们已经设置了readerwriter,让我们编译项目。

mvn clean install

序列化 Java 对象

现在,编译后,让我们先执行writer

java -cp .	arget\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 .	arget\flatbuffers-tutorial-1.0.jar com.tutorialspoint.theater.TheaterReader

Reading from file theater_flatbuffers_output
Drive In: true

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

Flat Buffers - enum

概述

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

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

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;

现在我们的包含一个枚举属性。我们为每个枚举常量分配了一个值,除了一个 DEBIT_CARD,默认情况下,它采用增量值 2。

我们定义枚举并将其用作下面的数据类型以及"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 {
      // 创建一个Flat Buffers构建器
      // 它将用于创建Theater  FlatBuffer
      FlatBufferBuilder builder = new FlatBufferBuilder(1024);

      // 使用 startTheater() 方法创建Theater  FlatBuffers
      Theater.startTheater(builder);
      // 向Theater  FlatBuffer 添加详细信息
      Theater.addPayment(builder, PAYMENT_SYSTEM.DEBIT_CARD);

      // 标记在 Gret FlatBuffer 中输入数据的结束
      int theater = Theater.endTheater(builder);

      // 完成构建器
      builder.finish(theater);

      // 获取要存储的字节
      byte[] data = builder.sizedByteArray();

      String filename = "theater_flatbuffers_output";
      System.out.println("Saving theater to file: " + filename);
      // 将构建器内容写入名为 theater_flatbuffers_output 的文件
      try(FileOutputStream output = new FileOutputStream(filename)){
         output.write(data);
      }
      System.out.println("Saved theater with following data to disk: 
" + theater);
   }
}	

接下来,我们将有一个阅读器来读取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)) {
         // 获取序列化数据
         byte[] data = input.readAllBytes();
         ByteBuffer buf = ByteBuffer.wrap(data);
         // 读取序列化数据中的根对象
         Theater theater = Theater.getRootAsTheater(buf);
         // 打印 theater 剧场值
         System.out.println("Payment Method: " + theater.payment());
      }
   }
}

编译项目

现在我们已经设置了readerwriter,让我们编译项目。

mvn clean install

序列化 Java 对象

现在,编译后,让我们先执行writer

> java -cp .	arget\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 .	arget\flatbuffers-tutorial-1.0.jar com.tutorialspoint.theater.TheaterReader

Reading from file theater_flatbuffers_output
Payment Method: 2

因此,如我们所见,我们能够通过将二进制数据反序列化为 Theater 对象来读取序列化的 enum。在下一章 Protocol Buffers - Vector 中,我们将研究复合类型向量。

Flat Buffers - Vector

概述

Vector 数据类型是 Flat Buffers 的复合数据类型之一。它相当于我们使用的语言中的数组列表,例如Java等。

继续Flat Buffers - String一章中的Theater 示例,以下是我们需要用来指示 FlatBuffers 我们将创建一个向量的语法 −

theater.fbs

namespace com.tutorialspoint.theater;

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

现在我们的 table 包含字符串和浮点数的 vector 属性。

从 fbs 文件创建 Java 类

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

flatc --java theater.fbs

这将在当前目录中的 com > tutorialspoint > theater 文件夹中创建一个 Theater.java 类。我们在应用程序中使用此类的方式与 Flat Buffers - Schema 一章中的方式类似。

使用从 fbs 文件创建的 Java 类

创建和写入向量

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

// 为字符串数组创建数据
int popcorn = builder.createString("Popcorn");
int coke = builder.createString("Coke");
int chips = builder.createString("Chips");
int soda = builder.createString("Soda");

// 为snacks(零食)创建数组
int[] snacks = {popcorn, coke, chip, soda};

// 为snacks(零食)向量创建偏移量
int snacksVector = Theater.createSnacksVector(builder, snacks);

// 向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 {
        // 创建一个Flat Buffers构建器
        // 它将用于创建Theater  FlatBuffer
        FlatBufferBuilder builder = new FlatBufferBuilder(1024);
        
        // 为字符串数组创建数据
        int popcorn = builder.createString("Popcorn");
        int coke = builder.createString("Coke");
        int chips = builder.createString("Chips");
        int soda = builder.createString("Soda");
        
        // 创建snacks(零食)数组
        int[] snacks = {爆米花、可乐、薯片、苏打水};
        
        // 创建票数数组
        float[] tickets = {100.0f, 100.f, 200.f};
        
        // 创建snacks(零食)向量偏移量
        int snacksVector = Theater.createSnacksVector(builder, snacks);
        
        // 创建票数向量偏移量
        int ticketsVector = Theater.createTicketsVector(builder, tickets);
        
        // 使用 startTheater() 方法创建Theater  FlatBuffers
        Theater.startTheater(builder);
        // 向Theater  FlatBuffer 添加详细信息
        Theater.addSnacks(builder, snacksVector);
        Theater.addTickets(builder, ticketsVector);       
        
        // 标记在 Gret FlatBuffer 中输入数据的结束
        int theater = Theater.endTheater(builder);
        
        // 完成构建器
        builder.finish(theater);
        
        // 获取要存储的字节
        byte[] data = builder.sizedByteArray();
        
        String filename = "theater_flatbuffers_output";
        System.out.println("Saving theater to file: " + filename);
        // 将构建器内容写入名为 theater_flatbuffers_output 的文件
        try(FileOutputStream output = new FileOutputStream(filename)){
         output.write(data);
      	}
      	System.out.println("Saved theater with following data to disk: 
" + theater);
   }
}	

读取向量

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

// 迭代由 snacksLength() 方法确定长度的snacks(零食)向量
for(int i = 0; i < theater.snacksLength(); i++ ) {
    // 通过其索引获取snacks(零食)
    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)) {
         // 获取序列化数据
         byte[] data = input.readAllBytes();
         ByteBuffer buf = ByteBuffer.wrap(data);
         // 读取序列化数据中的根对象
         Theater theater = Theater.getRootAsTheater(buf);
         // 打印 theater 剧场值
         System.out.println("Snacks: ");
         for(int i = 0; i < theater.snacksLength(); i++ ) {
            System.out.print(" " + theater.snacks(i));
         }
         System.out.println("
Tickets: ");
         for(int i = 0; i < theater.ticketsLength(); i++ ) {
            System.out.print(" " + theater.tickets(i));
         }         
      }
   }
}

编译项目

现在我们已经设置了readerwriter,让我们编译项目。

mvn clean install

序列化 Java 对象

现在,编译后,让我们先执行writer

> java -cp .	arget\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 .	arget\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 中,我们将介绍扇区,这是一种复合类型。

Flat Buffers - struct

概述

struct 数据类型是 Flat Buffers 的复合数据类型之一。它用于创建不可变的数据结构。结构占用的内存较少,查找速度相当快。结构通常是标量类型的组合。

继续使用 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;

现在我们的 table 包含定义为 Position 类型位置的 struct 属性。Position 是一个定义三个 int 数据结构的结构。

从 fbs 文件创建 Java 类

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

flatc --java theater.fbs

这将在当前目录的 com > tutorialspoint > theater 文件夹中创建 TheaterPosition 类。我们在应用程序中使用此类的方式与 Flat Buffers - Schema 一章中的方式类似。

使用从 fbs 文件创建的 Java 类

创建和编写结构体

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

// 为位置结构体创建偏移量
int location = Position.createPosition(builder, 100, 110, 120);

// 向Theater  FlatBuffer 添加详细信息
Theater.addLocation(builder, location); 

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

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 {
      // 创建一个Flat Buffers构建器
      // 它将用于创建Theater  FlatBuffer
      FlatBufferBuilder builder = new FlatBufferBuilder(1024);

      // create offset for location struct
      int location = Position.createPosition(builder, 100, 110, 120);
      
      // 使用 startTheater() 方法创建Theater  FlatBuffers
      Theater.startTheater(builder);
      // 向Theater  FlatBuffer 添加详细信息
      Theater.addLocation(builder, location);      

      // 标记在 Gret FlatBuffer 中输入数据的结束
      int theater = Theater.endTheater(builder);

      // 完成构建器
      builder.finish(theater);

      // 获取要存储的字节
      byte[] data = builder.sizedByteArray();

      String filename = "theater_flatbuffers_output";
      System.out.println("Saving theater to file: " + filename);
      // 将构建器内容写入名为 theater_flatbuffers_output 的文件
      try(FileOutputStream output = new FileOutputStream(filename)){
         output.write(data);
      }
      System.out.println("Saved theater with following data to disk: 
" + theater);
   }
}	

读取结构体

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

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

以下示例代码显示了读取 int 结构的过程。

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)) {
         // 获取序列化数据
         byte[] data = input.readAllBytes();
         ByteBuffer buf = ByteBuffer.wrap(data);
         // 读取序列化数据中的根对象
         Theater theater = Theater.getRootAsTheater(buf);
         // 打印 theater 剧场值
         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());        
      }
   }
}

编译项目

现在我们已经设置了readerwriter,让我们编译项目。

mvn clean install

序列化 Java 对象

现在,编译后,让我们先执行writer

> java -cp .	arget\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 .	arget\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 中,我们将研究 union,一种复合类型。

Flat Buffers - union

概述

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

继续使用 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 的 union 属性。在 Theater 表中,我们定义了 union 类型的 people,这意味着我们可以将任何 Employee 或 Viewer 存储在 people 变量中。

从 fbs 文件创建 Java 类

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

flatc --java theater.fbs

这将在当前目录的 com > tutorialspoint > theater 文件夹中创建 TheaterPeopleEmployeeViewer 类。我们在应用程序中使用此类的方式与 Flat Buffers - Schema 一章中的方式类似。

使用从 fbs 文件创建的 Java 类

创建和编写 Union

为了创建 Union,我们首先需要准备所需类型的偏移量,例如 Viewer,然后我们可以将查看器及其类型添加到Flat Buffers。

// 为 Viewer 创建偏移量
int viewerName = builder.createString("Mery");
int viewerAddress = builder.createString("Avenue 4");
int viewer = Viewer.createViewer(builder, viewerName, viewerAddress);

//添加 union 类型
Theater.addPeopleType(builder, People.Viewer);
// 向Theater  FlatBuffer 添加详细信息
Theater.addPeople(builder, viewer);

以下示例代码展示了创建 Union 的过程。

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 {
        // 创建一个Flat Buffers构建器
        // 它将用于创建Theater  FlatBuffer
        FlatBufferBuilder builder = new FlatBufferBuilder(1024);
        
        // 为 Viewer 创建偏移量
        int viewerName = builder.createString("Mery");
        int viewerAddress = builder.createString("Avenue 4");
        int viewer = Viewer.createViewer(builder, viewerName, viewerAddress);
        
        // 为向量创建偏移量
        //int people = Theater.createPeople
        
        // 使用 startTheater() 方法创建Theater  FlatBuffers
        Theater.startTheater(builder);
        
        //add union type
        Theater.addPeopleType(builder, People.Viewer);
        
        // 向Theater  FlatBuffer 添加详细信息
        Theater.addPeople(builder, viewer);
        
        // 标记在 Gret FlatBuffer 中输入数据的结束
        int theater = Theater.endTheater(builder);
        
        // 完成构建器
        builder.finish(theater);
        
        // 获取要存储的字节
        byte[] data = builder.sizedByteArray();
        
        String filename = "theater_flatbuffers_output";
        System.out.println("Saving theater to file: " + filename);
        // 将构建器内容写入名为 theater_flatbuffers_output 的文件
        try(FileOutputStream output = new FileOutputStream(filename)){
         output.write(data);
      	}
      	System.out.println("Saved theater with following data to disk: 
" + theater);
   }
}	

读取 Union

为了读取 Union,我们可以检查 union 对象的类型,然后相应地检索值。

// 获取保存的 union 类型
int unionType = theater.peopleType();

// 如果 union 是 Viewer 类型
if(unionType == People.Viewer) {
   Viewer viewer = (Viewer)theater.people(new Viewer());
   System.out.println("Name: " + viewer.name());
   System.out.println("Address: " + viewer.address());       	 
} 
// 如果 union 是 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()); 
}

以下示例代码展示了读取 Union 的过程。

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)) {
         // 获取序列化数据
         byte[] data = input.readAllBytes();
         ByteBuffer buf = ByteBuffer.wrap(data);
         // 读取序列化数据中的根对象
         Theater theater = Theater.getRootAsTheater(buf);
         // 打印 theater 剧场值
        System.out.println("People: ");
        // 获取 union 的类型
        int unionType = theater.peopleType();
        // 如果 union 是 Viewer 类型
         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()); 
         }       
      }
   }
}

编译项目

现在我们已经设置了readerwriter,让我们编译项目。

mvn clean install

序列化 Java 对象

现在,编译后,让我们先执行writer

> java -cp .	arget\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 .	arget\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 - Nested Tables 中,我们将了解复合类型嵌套表。

Flat Buffers - Nested Table

概述

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

继续使用 Flat Buffers - String 一章中的 theater 示例,以下是我们需要用来指示 FlatBuffers 创建 嵌套表 的语法 −

theater.fbs

namespace com.tutorialspoint.theater;

table Theater {
   owner: TheaterOwner;
}

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

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

从 fbs 文件创建 Java 类

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

flatc --java theater.fbs

这将在当前目录中的 com > tutorialspoint > theater 文件夹中创建 Theater 和 TheaterOwner 类。我们在应用程序中使用此类的方式与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 {
      // 创建一个Flat Buffers构建器
      // 它将用于创建Theater  FlatBuffer
      FlatBufferBuilder builder = new FlatBufferBuilder(1024);
      
      // 为 TheaterOwner 创建偏移量
      int ownerName = builder.createString("Mery");
      int ownerAddress = builder.createString("Avenue 4");
      int owner = TheaterOwner.createTheaterOwner(builder, ownerName, ownerAddress);
      
      // 使用 startTheater() 方法创建Theater  FlatBuffers
      Theater.startTheater(builder);
      // 向Theater  FlatBuffer 添加详细信息
      Theater.addOwner(builder, owner);      
      
      // 标记在 Gret FlatBuffer 中输入数据的结束
      int theater = Theater.endTheater(builder);

      // 完成构建器
      builder.finish(theater);

      // 获取要存储的字节
      byte[] data = builder.sizedByteArray();

      String filename = "theater_flatbuffers_output";
      System.out.println("Saving theater to file: " + filename);
      // 将构建器内容写入名为 theater_flatbuffers_output 的文件
      try(FileOutputStream output = new FileOutputStream(filename)){
         output.write(data);
      }
      System.out.println("Saved theater with following data to disk: 
" + theater);
   }
}	

接下来,我们将有一个阅读器来读取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)) {
         // 获取序列化数据
         byte[] data = input.readAllBytes();
         ByteBuffer buf = ByteBuffer.wrap(data);
         // 读取序列化数据中的根对象
         Theater theater = Theater.getRootAsTheater(buf);
         // 打印 theater 剧场值
         System.out.println("Owner Details: ");
         TheaterOwner owner = theater.owner();
         System.out.println("Name: " + owner.name());
         System.out.println("Address: " + owner.address());        
      }
   }
}

编译项目

现在我们已经设置了readerwriter,让我们编译项目。

mvn clean install

序列化 Java 对象

现在,编译后,让我们先执行writer

java -cp .	arget\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 .	arget\flatbuffers-tutorial-1.0.jar com.tutorialspoint.theater.TheaterReader

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

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

Flat Buffers - 默认值

概述

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

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

数据类型 默认值
int16 / short / int / long 0
Float/double 0.0
String Empty string
Boolean False
Enum 第一个枚举项,即"index=0"的项
Vector Empty list
Nested Class null

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

在此示例中,我们将让所有字段都采用默认值。唯一需要指定的字段是Theater 的名称。

继续使用 Flat Buffers - String 章节中的 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 - 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 {
      // 创建一个Flat Buffers构建器
      // 它将用于创建Theater  FlatBuffer
      FlatBufferBuilder builder = new FlatBufferBuilder(1024);
      
      // 为 name 名称创建偏移量
      int name = builder.createString("Mery");
      
      // 使用 startTheater() 方法创建Theater  FlatBuffers
      Theater.startTheater(builder);
      // 向Theater  FlatBuffer 添加详细信息
      Theater.addName(builder, name);      
      
      // 标记在 Gret FlatBuffer 中输入数据的结束
      int theater = Theater.endTheater(builder);

      // 完成构建器
      builder.finish(theater);

      // 获取要存储的字节
      byte[] data = builder.sizedByteArray();

      String filename = "theater_flatbuffers_output";
      System.out.println("Saving theater to file: " + filename);
      // 将构建器内容写入名为 theater_flatbuffers_output 的文件
      try(FileOutputStream output = new FileOutputStream(filename)){
         output.write(data);
      }
      System.out.println("Saved theater with following data to disk: 
" + theater);
   }
}	

接下来,我们将有一个阅读器来读取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)) {
         // 获取序列化数据
         byte[] data = input.readAllBytes();
         ByteBuffer buf = ByteBuffer.wrap(data);
         // 读取序列化数据中的根对象
         Theater theater = Theater.getRootAsTheater(buf);

         // 打印 theater 剧场值
         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);
         }        
      }
   }
}

编译项目

现在我们已经设置了readerwriter,让我们编译项目。

mvn clean install

序列化 Java 对象

现在,编译后,让我们先执行writer

java -cp .	arget\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 .	arget\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 对象来读取默认值。

Flat Buffers - JSON 到二进制

概述

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

考虑以下携带 Theater 对象信息的 JSON

theater.json


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

theater.fbs

这是我们的 Flat Buffers Schema 文件

namespace com.tutorialspoint.theater;

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

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

flatc --binary theater.fbs theater.json

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

从 fbs 文件创建 Java 类

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

flatc --java theater.fbs

这将在当前目录的 com > tutorialspoint > theater 文件夹中创建一个 Theater 类。我们在应用程序中使用此类的方式与Flat Buffers - Schema一章中的方式类似。

使用从 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)) {
         // 获取序列化数据
         byte[] data = input.readAllBytes();
         ByteBuffer buf = ByteBuffer.wrap(data);
         // 读取序列化数据中的根对象
         Theater theater = Theater.getRootAsTheater(buf);
         // 打印 theater 剧场值
         System.out.println("Name: " + theater.name());
         System.out.println("Address: " + theater.address());
         System.out.println("Mobile: " + theater.mobile());        
      }
   }
}

编译项目

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

mvn clean install

反序列化序列化对象

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

java -cp .	arget\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 对象来读取默认值。

Flat Buffers - 二进制到 JSON

概述

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

考虑上一章 Flat Buffers - JSON to Binary 中创建的 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
}

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

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 提供的具有 const 访问器的类来读取此文件。这有助于在多个读取器中使用Flat Buffers文件。但有时,我们可能需要在读取后修改某个值,并需要将修改后的值传递给下一个读取器。我们可以通过从头开始创建一个新的Flat Buffers来实现这一点,这对于大的变化来说更好、更高效。对于小改动,Flat Buffers 为 flatc complier 提供了一个选项 --gen-mutable,用于生成非常量访问器来修改 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 {
      // 创建一个Flat Buffers构建器
      // 它将用于创建Theater  FlatBuffer
      FlatBufferBuilder builder = new FlatBufferBuilder(1024);

      // 为名字和地址创建偏移量
      int name = builder.createString("Silver Screener");
      int address = builder.createString("212, Maple Street, LA, California");
      
      // 使用 startTheater() 方法创建Theater  FlatBuffers
      Theater.startTheater(builder);
      // 向Theater  FlatBuffer 添加详细信息
      Theater.addName(builder, name);   
      Theater.addAddress(builder, address);
      Theater.addMobile(builder, 12233345);

      // 标记在 Gret FlatBuffer 中输入数据的结束
      int theater = Theater.endTheater(builder);

      // 完成构建器
      builder.finish(theater);

      // 获取要存储的字节
      byte[] data = builder.sizedByteArray();

      String filename = "theater_flatbuffers_output";
      System.out.println("Saving theater to file: " + filename);
      // 将构建器内容写入名为 theater_flatbuffers_output 的文件
      try(FileOutputStream output = new FileOutputStream(filename)){
         output.write(data);
      }
      System.out.println("Saved theater with following data to disk: 
" + theater);
   }
}	

接下来,我们将有一个阅读器来读取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)) {
         // 获取序列化数据
         byte[] data = input.readAllBytes();
         ByteBuffer buf = ByteBuffer.wrap(data);
         // 读取序列化数据中的根对象
         Theater theater = Theater.getRootAsTheater(buf);
         // 打印 theater 剧场值
         System.out.println("Name: " + theater.name());
         System.out.println("Address: " + theater.address());
         System.out.println("Mobile: " + theater.mobile());
         
         
         // 更新 mobile
         theater.mutateMobile(22333341);
         
         // 我们可以再次编写 theater 对象以将其进一步发送
         // read the updated mobile value
         System.out.println("Updated Mobile: " + theater.mobile());
      }
   }
}

编译项目

现在我们已经设置了readerwriter,让我们编译项目。

mvn clean install

序列化 Java 对象

现在,编译后,让我们先执行writer

java -cp .	arget\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 .	arget\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

Flat Buffers - 语言独立性

概述

到目前为止,我们一直使用 Java 来序列化和反序列化电影院数据。但是,Google Flat 缓冲区提供的关键功能之一是"语言独立性"。在本章中,我们将了解如何使用 Java 进行序列化并使用 Python 进行反序列化。

继续使用Flat Buffers - String一章中的Theater 示例,以下是我们在本示例中使用的模式 −

theater.fbs

namespace com.tutorialspoint.theater;

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

使用 Java 进行序列化

要使用 Flat Buffers,我们现在必须使用 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 {
      // 创建一个Flat Buffers构建器
      // 它将用于创建Theater  FlatBuffer
      FlatBufferBuilder builder = new FlatBufferBuilder(1024);

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

      // 使用 startTheater() 方法创建Theater  FlatBuffers
      Theater.startTheater(builder);
      // add the name and address to the Theater FlatBuffer
      Theater.addName(builder, name);
      Theater.addAddress(builder, address);

      // 标记在 Gret FlatBuffer 中输入数据的结束
      int theater = Theater.endTheater(builder);

      // 完成构建器
      builder.finish(theater);

      // 获取要存储的字节
      byte[] data = builder.sizedByteArray();

      String filename = "theater_flatbuffers_output";
      System.out.println("Saving theater to file: " + filename);
      // 将构建器内容写入名为 theater_flatbuffers_output 的文件
      try(FileOutputStream output = new FileOutputStream(filename)){
         output.write(data);
      }
      System.out.println("Saved theater with following data to disk: 
" + theater);
   }
}	

编译项目

现在我们已经设置了readerwriter,让我们编译项目。

mvn clean install

序列化 Java 对象

现在,编译后,让我们先执行writer

java -cp .	arget\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 与语言无关。

Flat Buffers - 向后兼容性

概述

FlatBuffers 模式向后兼容。这意味着,如果我们稍后将属性添加到 flatbuffers 模式,现有代码仍然可以工作。这在维护旧代码库时非常有用。考虑一个 Theater Schema 仅包含名称和地址的场景,如下所示:

theater.fbs

namespace com.tutorialspoint.theater;

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

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

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

从 fbs 文件创建 Java 类

要使用Flat Buffers,我们现在必须使用 flatc 二进制文件从此".fbs"文件创建所需的类。让我们看看如何做到这一点 −

flatc --java theater.fbs

这将在 com > 中创建一个 Theater.java 类tutorialspoint > theater 文件夹。我们在应用程序中使用此类的方式与 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 {
      // 创建一个Flat Buffers构建器
      // 它将用于创建Theater  FlatBuffer
      FlatBufferBuilder builder = new FlatBufferBuilder(1024);

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

      // 使用 startTheater() 方法创建Theater  FlatBuffers
      Theater.startTheater(builder);
      // add the name and address to the Theater FlatBuffer
      Theater.addName(builder, name);
      Theater.addAddress(builder, address);

      // 标记在 Gret FlatBuffer 中输入数据的结束
      int theater = Theater.endTheater(builder);

      // 完成构建器
      builder.finish(theater);

      // 获取要存储的字节
      byte[] data = builder.sizedByteArray();

      String filename = "theater_flatbuffers_output";
      System.out.println("Saving theater to file: " + filename);
      // 将构建器内容写入名为 theater_flatbuffers_output 的文件
      try(FileOutputStream output = new FileOutputStream(filename)){
         output.write(data);
      }
      System.out.println("Saved theater with following data to disk: 
" + theater);
   }
}	

接下来,我们将有一个阅读器来读取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)) {
         // 获取序列化数据
         byte[] data = input.readAllBytes();
         ByteBuffer buf = ByteBuffer.wrap(data);
         // 读取序列化数据中的根对象
         Theater theater = Theater.getRootAsTheater(buf);
         // 打印 theater 剧场值
         
         System.out.println("Name: " + theater.name());
         System.out.println("Address: " + theater.address());
      }
   }
}

编译项目

现在我们已经设置了readerwriter,让我们编译项目。

mvn clean install

序列化 Java 对象

现在,编译后,让我们先执行writer

java -cp .	arget\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 .	arget\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 {
      // 创建一个Flat Buffers构建器
      // 它将用于创建Theater  FlatBuffer
      FlatBufferBuilder builder = new FlatBufferBuilder(1024);

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

      // 使用 startTheater() 方法创建Theater  FlatBuffers
      Theater.startTheater(builder);
      // 将姓名、地址和手机添加到 Theater FlatBuffer
      Theater.addName(builder, name);
      Theater.addAddress(builder, address);
      Theater.addMobile(builder, 12233345);

      // 标记在 Gret FlatBuffer 中输入数据的结束
      int theater = Theater.endTheater(builder);

      // 完成构建器
      builder.finish(theater);

      // 获取要存储的字节
      byte[] data = builder.sizedByteArray();

      String filename = "theater_flatbuffers_output";
      System.out.println("Saving theater to file: " + filename);
      // 将构建器内容写入名为 theater_flatbuffers_output 的文件
      try(FileOutputStream output = new FileOutputStream(filename)){
         output.write(data);
      }
      System.out.println("Saved theater with following data to disk: 
" + theater);
   }
}	

编译项目

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

mvn clean install

序列化 Java 对象

现在,编译后,让我们首先执行 writer

java -cp .	arget\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 .	arget\flatbuffers-tutorial-1.0.jar com.tutorialspoint.theater.TheaterReader

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

更新 Reader 并再次反序列化

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)) {
         // 获取序列化数据
         byte[] data = input.readAllBytes();
         ByteBuffer buf = ByteBuffer.wrap(data);
         // 读取序列化数据中的根对象
         Theater theater = Theater.getRootAsTheater(buf);
         // 打印 theater 剧场值
         
         System.out.println("Name: " + theater.name());
         System.out.println("Address: " + theater.address());
         System.out.println("Mobile: " + theater.mobile());
      }
   }
}

编译项目

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

mvn clean install

反序列化序列化对象

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

java -cp .	arget\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