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 只是从同一个文件中读取数据,对其进行反序列化,然后打印有关问候语的数据。

编译项目

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

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());
      }
   }
}

编译项目

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

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());
      }
   }
}

编译项目

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

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,例如 Java、Python 等。

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

编译项目

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

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());
      }
   }
}

编译项目

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

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));
         }         
      }
   }
}

编译项目

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

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 文件夹中创建 Theater 和 Position 类。我们在应用程序中使用此类的方式与 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());        
      }
   }
}

编译项目

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

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 文件夹中创建 Theater、People、Employee 和 Viewer 类。我们在应用程序中使用此类的方式与 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()); 
         }       
      }
   }
}

编译项目

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

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());        
      }
   }
}

编译项目

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

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);
         }        
      }
   }
}

编译项目

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

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());
      }
   }
}

编译项目

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

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);
   }
}	

编译项目

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

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());
      }
   }
}

编译项目

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

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