Different Serialization Approaches for Java – Java的不同序列化方法

最后修改: 2021年 7月 4日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

Serialization is the process of converting an object into a stream of bytes. That object can then be saved to a database or transferred over a network. The opposite operation, extracting an object from a series of bytes, is deserialization. Their main purpose is to save the state of an object so that we can recreate it when needed.

序列化是将一个对象转换为字节流的过程。然后,该对象可以被保存到数据库或通过网络传输。相反的操作,从一系列的字节中提取一个对象,就是反序列化。它们的主要目的是保存一个对象的状态,以便我们在需要时可以重新创建它。

In this tutorial, we’ll explore different serialization approaches for Java objects.

在本教程中,我们将探讨Java对象的不同序列化方法

First, we’ll discuss Java’s Native APIs for serialization. Next, we’ll explore libraries that support JSON and YAML formats to do the same. Finally, we’ll take a look at some cross-language protocols.

首先,我们将讨论Java的Native APIs进行序列化。接下来,我们将探讨支持JSON和YAML格式的库来做同样的事情。最后,我们将看一下一些跨语言的协议。

2. Sample Entity Class

2.实体类样本

Let’s start by introducing a simple entity that we’re going to use throughout this tutorial:

让我们从介绍一个简单的实体开始,我们将在本教程中使用这个实体。

public class User {
    private int id;
    private String name;
    
    //getters and setters
}

In the next sections, we’ll go through the most widely used serialization protocols. Through examples, we’ll learn the basic usage of each of them.

在接下来的章节中,我们将介绍最广泛使用的序列化协议。通过例子,我们将学习它们中每一个的基本用法。

3. Java’s Native Serialization

3.Java的本地序列化

Serialization in Java helps to achieve effective and prompt communication between multiple systems. Java specifies a default way to serialize objects. A Java class can override this default serialization and define its own way of serializing objects.

Java中的序列化有助于实现多个系统之间有效而迅速的通信。Java指定了一种默认的方法来序列化对象。一个Java类可以覆盖这种默认的序列化,并定义它自己的序列化对象的方式。

The advantages of Java native serialization are:

Java本地序列化的优势在于。

  • It’s a simple yet extensible mechanism
  • It maintains the object type and safety properties in the serialized form
  • Extensible to support marshaling and unmarshaling as needed for remote objects
  • This is a native Java solution, so it doesn’t require any external libraries

3.1. The Default Mechanism

3.1.默认机制

As per the Java Object Serialization Specification, we can use the writeObject() method from ObjectOutputStream class to serialize the object. On the other hand, we can use the readObject() method, which belongs to the ObjectInputStream class, to perform the deserialization.

根据Java对象序列化规范,我们可以使用ObjectOutputStream类中的writeObject()方法来序列化该对象。另一方面,我们可以使用属于ObjectInputStream类的readObject()方法来执行反序列化。

We’ll illustrate the basic process with our User class.

我们将用我们的用户类来说明这个基本过程。

First, our class needs to implement the Serializable interface:

首先,我们的类需要实现Serializable/em>接口

public class User implements Serializable {
    //fields and methods
}

Next, we need to add the serialVersionUID attribute:

接下来,我们需要添加serialVersionUID属性

private static final long serialVersionUID = 1L;

Now, let’s create a User object:

现在,让我们创建一个User对象。

User user = new User();
user.setId(1);
user.setName("Mark");

We need to provide a file path to save our data:

我们需要提供一个文件路径来保存我们的数据。

String filePath = "src/test/resources/protocols/user.txt";

Now, it’s time to serialize our User object to a file:

现在,是时候将我们的User对象序列化到一个文件了。

FileOutputStream fileOutputStream = new FileOutputStream(filePath);
ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
objectOutputStream.writeObject(user);

Here, we used ObjectOutputStream for saving the state of the User object to a “user.txt” file.

这里,我们使用ObjectOutputStream来保存User对象的状态到“user.txt”文件。

On the other hand, we can read the User object from the same file and deserialize it:

另一方面,我们可以从同一个文件中读取User对象并反序列化它。

FileInputStream fileInputStream = new FileInputStream(filePath);
ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
User deserializedUser = (User) objectInputStream.readObject();

Finally, we can test the state of the loaded object:

最后,我们可以测试加载对象的状态。

assertEquals(1, deserializedUser.getId());
assertEquals("Mark", deserializedUser.getName());

This is the default way to serialize Java objects. In the next section, we’ll see the custom way to do the same.

这是将Java对象序列化的默认方式。在下一节中,我们将看到自定义的方式来做同样的事情。

3.2. Custom Serialization Using the Externalizable Interface

3.2.使用Externalizable接口进行自定义序列化

Custom serialization can be particularly useful when trying to serialize an object that has some unserializable attributes. This can be done by implementing the Externalizable interface, which has two methods:

当试图序列化一个具有一些不可序列化属性的对象时,自定义序列化可能特别有用。这可以通过实现Externalizable接口来实现,它有两个方法。

public void writeExternal(ObjectOutput out) throws IOException;

public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException;

We can implement these two methods inside the class that we want to serialize. A detailed example can be found in our article on the Externalizable Interface.

我们可以在我们想要序列化的类中实现这两个方法。在我们关于Externalizable接口的文章中可以找到一个详细的例子。

3.3. Java Serialization Caveats

3.3.Java序列化注意事项

There are some caveats that concern native serialization in Java:

有一些注意事项涉及到Java中的本地序列化。

  • Only objects marked Serializable can be persisted. The Object class does not implement Serializable, and hence, not all the objects in Java can be persisted automatically
  • When a class implements the Serializable interface, all its sub-classes are serializable as well. However, when an object has a reference to another object, these objects must implement the Serializable interface separately, or else a NotSerializableException will be thrown
  • If we want to control the versioning, we need to provide the serialVersionUID attribute. This attribute is used to verify that the saved and loaded objects are compatible. Therefore, we need to ensure it is always the same, or else InvalidClassException will be thrown
  • Java serialization heavily uses I/O streams. We need to close a stream immediately after a read or write operation because if we forget to close the stream, we’ll end up with a resource leak. To prevent such resource leaks, we can use the try-with-resources idiom

4. Gson Library

4.格森图书馆

Google’s Gson is a Java library that is used to serialize and deserialize Java objects to and from JSON representation.

Google的Gson是一个Java库,用于将Java对象序列化和反序列化为JSON表示。

Gson is an open-source project hosted in GitHub. In general, it provides toJson() and fromJson() methods to convert Java objects to JSON and vice versa.

Gson是一个开源项目,托管在GitHub。一般来说,它提供toJson()fromJson()方法来将Java对象转换成JSON,反之亦然。

4.1. Maven Dependency

4.1.Maven的依赖性

Let’s add the dependency for the Gson library:

让我们添加Gson库的依赖性。

<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>2.8.7</version>
</dependency>

4.2. Gson Serialization

4.2.Gson序列化

First, let’s create a User object:

首先,让我们创建一个User对象。

User user = new User();
user.setId(1);
user.setName("Mark");

Next, we need to provide a file path to save our JSON data:

接下来,我们需要提供一个文件路径来保存我们的JSON数据。

String filePath = "src/test/resources/protocols/gson_user.json";

Now, let’s use the toJson() method from the Gson class to serialize the User object into the “gson_user.json” file:

现在,让我们使用Gson类中的toJson()方法,将User对象序列化为”gson_user.json”文件。

Writer writer = new FileWriter(filePath);
Gson gson = new GsonBuilder().setPrettyPrinting().create();
gson.toJson(user, writer);

4.3. Gson Deserialization

4.3.Gson反序列化

We can use the fromJson() method from the Gson class to deserialize the JSON data.

我们可以使用Gson类中的fromJson()方法来反序列化JSON数据。

Let’s read the JSON file and deserialize the data into a User object:

让我们读取JSON文件并将数据反序列化为一个User对象。

Gson gson = new GsonBuilder().setPrettyPrinting().create();
User deserializedUser = gson.fromJson(new FileReader(filePath), User.class);

Finally, we can test the deserialized data:

最后,我们可以测试反序列化的数据。

assertEquals(1, deserializedUser.getId());
assertEquals("Mark", deserializedUser.getName());

4.4. Gson Features

4.4.Gson的特点

Gson has many important features, including:

Gson有许多重要的功能,包括。

  • It can handle collections, generic types, and nested classes
  • With Gson, we can also write a custom serializer and/or deserializer so that we can control the whole process
  • Most importantly, it allows deserializing instances of classes for which the source code is not accessible
  • In addition, we can use a versioning feature in case our class file has been modified in different versions. We can use the @Since annotation on newly added fields, and then we can use the setVersion() method from GsonBuilder

For more examples, please check our cookbooks for Gson Serialization and Gson Deserialization.

关于更多的例子,请查看我们的Gson序列化Gson反序列化的烹饪书。

In this section, we serialized data in the JSON format using Gson API. In the next section, we’ll use the Jackson API to do the same.

在本节中,我们使用Gson API将数据序列化为JSON格式。在下一节中,我们将使用Jackson API来做同样的事情。

5. Jackson API

5.JacksonAPI

Jackson is also known as “the Java JSON library” or “the best JSON parser for Java”. It provides multiple approaches to work with JSON data.

Jackson也被称为 “Java JSON库 “或 “Java的最佳JSON解析器”。它提供了多种方法来处理JSON数据。

To understand the Jackson library in general, our Jackson Tutorial is a good place to start.

要了解Jackson库的总体情况,我们的Jackson教程是一个不错的开始。

5.1. Maven Dependency

5.1.Maven的依赖性

Let’s add the dependency for the Jackson libraries:

让我们添加Jackson库的依赖性。

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
    <version>2.12.4</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-annotations</artifactId>
    <version>2.12.4</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
     <version>2.12.4</version>
</dependency>

5.2. Java Object to JSON

5.2.Java对象到JSON

We can use the writeValue() method, which belongs to the ObjectMapper class, to serialize any Java object as JSON output.

我们可以使用属于ObjectMapper类的writeValue()方法,将任何Java对象序列化为JSON输出。

Let’s start by creating a User object:

让我们从创建一个User对象开始。

User user = new User();
user.setId(1);
user.setName("Mark Jonson");

After that, let’s provide a file path to store our JSON data:

之后,让我们提供一个文件路径来存储我们的JSON数据。

String filePath = "src/test/resources/protocols/jackson_user.json";

Now, we can store a User object into a JSON file using the ObjectMapper class:

现在,我们可以使用ObjectMapper类将User对象存储到一个JSON文件。

File file = new File(filePath);
ObjectMapper mapper = new ObjectMapper();
mapper.writeValue(file, user);

This code will write our data to the “jackson_user.json” file.

这段代码将把我们的数据写入“jackson_user.json”/em>文件。

5.3. JSON to Java Object

5.3 JSON到Java对象

The simple readValue() method of the ObjectMapper is a good entry point. We can use it to deserialize JSON content into a Java object.

ObjectMapper的简单readValue()方法是一个很好的切入点。我们可以用它来将JSON内容反序列化为一个Java对象。

Let’s read the User object from the JSON file:

让我们从JSON文件中读取User对象。

User deserializedUser = mapper.readValue(new File(filePath), User.class);

We can always test the loaded data:

我们可以随时测试加载的数据。

assertEquals(1, deserializedUser.getId());
assertEquals("Mark Jonson", deserializedUser.getName());

5.4. Jackson Features

5.4.Jackson的特点

  • Jackson is a solid and mature JSON serialization library for Java
  • The ObjectMapper class is the entry point of the serialization process and provides a straightforward way to parse and generate JSON objects with a lot of flexibility
  • One of the greatest strengths of the Jackson library is the highly customizable serialization and deserialization process

Until now, we saw data serialization in the JSON format. In the next section, we’ll explore serialization using YAML.

到目前为止,我们看到的是JSON格式的数据序列化。在下一节中,我们将探讨使用YAML进行序列化。

6. YAML

6.YAML

YAML stands for “YAML Ain’t Markup Language”. It is a human-readable data serialization language. We can use YAML for configuration files, as well as in the applications where we want to store or transmit data.

YAML代表了 “YAML Ain’t Markup Language”。它是一种人类可读的数据序列化语言。我们可以将YAML用于配置文件,也可以在我们想要存储或传输数据的应用程序中使用。

In the previous section, we saw the Jackson API process JSON files. We can also use Jackson APIs to process YAML files. A detailed example can be found in our article on parsing YAML with Jackson.

在上一节中,我们看到Jackson API处理JSON文件。我们还可以使用Jackson API来处理YAML文件。在我们关于用Jackson解析YAML的文章中可以找到一个详细的例子。

Now, let’s take a look at other libraries.

现在,让我们来看看其他图书馆。

6.1. YAML Beans

6.1.YAML Bean

YAML Beans makes it easy to serialize and deserialize Java object graphs to and from YAML.

YAML Beans使其能够轻松地将Java对象图序列化和反序列化为YAML。

The YamlWriter class is used to serialize Java objects to YAML. The write() method automatically handles this by recognizing public fields and the bean’s getter methods.

YamlWriter类用于将Java对象序列化为YAML。write()方法通过识别公共字段和Bean的getter方法自动处理。

Conversely, we can use the YamlReader class to deserialize YAML to Java objects. The read() method reads the YAML document and deserializes it into the required object.

相反,我们可以使用YamlReader类来将YAML反序列化为Java对象。read()方法读取YAML文档并将其反序列化为所需对象。

First of all, let’s add the dependency for YAML Beans:

首先,让我们添加YAMLBean的依赖性

<dependency>
    <groupId>com.esotericsoftware.yamlbeans</groupId>
    <artifactId>yamlbeans</artifactId>
    <version>1.15</version>
</dependency>

Now. let’s create a map of User objects:

现在,让我们创建一个User对象的地图。

private Map<String, User> populateUserMap() {
    User user1 = new User();
    user1.setId(1);
    user1.setName("Mark Jonson");
    //.. more user objects
    
    Map<String, User> users = new LinkedHashMap<>();
    users.put("User1", user1);
    // add more user objects to map
    
    return users;
}

After that, we need to provide a file path to store our data:

之后,我们需要提供一个文件路径来存储我们的数据。

String filePath = "src/test/resources/protocols/yamlbeans_users.yaml";

Now, we can use the YamlWriter class to serialize the map into a YAML file:

现在,我们可以使用YamlWriter类来将地图序列化为YAML文件。

YamlWriter writer = new YamlWriter(new FileWriter(filePath));
writer.write(populateUserMap());
writer.close();

On the opposite side, we can use the YamlReader class to deserialize the map:

在另一边,我们可以使用YamlReader类来反序列化地图。

YamlReader reader = new YamlReader(new FileReader(filePath));
Object object = reader.read();
assertTrue(object instanceof Map); 

Finally, we can test the loaded map:

最后,我们可以测试加载的地图。

Map<String, User> deserializedUsers = (Map<String, User>) object;
assertEquals(4, deserializedUsers.size());
assertEquals("Mark Jonson", (deserializedUsers.get("User1").getName()));
assertEquals(1, (deserializedUsers.get("User1").getId()));

6.2. SnakeYAML

6.2. SnakeYAML

SnakeYAML provides a high-level API to serialize Java objects to YAML documents and vice versa. The latest version, 1.2, can be used with JDK 1.8 or higher Java versions. It can parse Java structures such as String, List, and Map.

SnakeYAML提供了一个高级API,用于将Java对象序列化为YAML文档,反之亦然。最新的1.2版本可以与JDK 1.8或更高的Java版本一起使用。它可以解析诸如StringListMap等Java结构。

The entry point for SnakeYAML is the Yaml class, which contains several methods that help in serialization and deserialization.

SnakeYAML的入口点是Yaml类,它包含了几个有助于序列化和反序列化的方法。

To deserialize YAML input into Java objects, we can load a single document with the load() method and multiple documents with the loadAll() method. These methods accept an InputStream, as well as String objects.

为了将YAML输入反序列化为Java对象,我们可以用load()方法加载单个文档,用loadAll()方法加载多个文档。这些方法接受一个InputStream,以及String对象。

Going the other direction, we can use the dump() method to serialize Java objects into YAML documents.

换个方向,我们可以使用 dump()方法将Java对象序列化为YAML文档。

A detailed example can be found in our article on parsing YAML with SnakeYAML.

一个详细的例子可以在我们关于用SnakeYAML解析YAML的文章中找到。

Naturally, SnakeYAML works well with Java Maps, however, it can work with custom Java objects as well.

自然,SnakeYAML与Java Maps配合得很好,但是,它也可以与自定义的Java对象配合。

In this section, we saw different libraries to serialize data into YAML format. In the next sections, we’ll discuss cross-platform protocols.

在本节中,我们看到了将数据序列化为YAML格式的不同库。在接下来的章节中,我们将讨论跨平台的协议。

7. Apache Thrift

7.Apache thrift

Apache Thrift was originally developed by Facebook and is currently maintained by Apache.

Apache Thrift最初由 Facebook 开发,目前由 Apache 维护。

The best benefit of using Thrift is that it supports cross-language serialization with lower overhead. Also, many serialization frameworks support only one serialization format, however, Apache Thrift allows us to choose from several.

使用Thrift的最大好处是,它支持跨语言序列化,开销较低。另外,许多序列化框架只支持一种序列化格式,然而,Apache Thrift允许我们从几种格式中选择。

7.1. Thrift Features

7.1.节俭的特点

Thrift provides pluggable serializers that are known as protocols. These protocols provide flexibility to use any one of several serialization formats for data exchange. Some examples of supported protocols include:

Thrift提供了被称为协议的可插拔序列化器。这些协议提供了灵活性,可以使用几种序列化格式中的任何一种来进行数据交换。支持的协议的一些例子包括。

  • TBinaryProtocol uses a binary format and hence faster to process than the text protocol
  • TCompactProtocol is a more compact binary format and, therefore, more efficient to process as well
  • TJSONProtocol uses JSON for encoding data

Thrift also supports the serialization of container types – lists, sets, and maps.

Thrift还支持容器类型的序列化–列表、集合和地图。

7.2. Maven Dependency

7.2.Maven依赖性

To use the Apache Thrift framework in our application, let’s add the Thrift libraries:

为了在我们的应用程序中使用Apache Thrift框架,让我们添加Thrift库

<dependency>
    <groupId>org.apache.thrift</groupId>
    <artifactId>libthrift</artifactId>
    <version>0.14.2</version>
</dependency>

7.3. Thrift Data Serialization

7.3.漂流数据序列化

Apache Thrift protocols and transports are designed to work together as a layered stack. The protocols serialize data into a byte stream, and the transports read and write the bytes.

Apache Thrift协议和运输工具被设计为作为一个分层堆栈一起工作。协议将数据序列化为字节流,而运输工具则读取和写入这些字节。

As stated earlier, Thrift provides a number of protocols. We’ll illustrate thrift serialization using a binary protocol.

如前所述,Thrift提供了许多协议。我们将用一个二进制协议来说明thrift的序列化。

First of all, we need a User object:

首先,我们需要一个User对象。

User user = new User();
user.setId(2);
user.setName("Greg");

The next step is to create a binary protocol:

下一步是创建一个二进制协议。

TMemoryBuffer trans = new TMemoryBuffer(4096);
TProtocol proto = new TBinaryProtocol(trans);

Now, let’s serialize our data. We can do so using the write APIs:

现在,让我们来序列化我们的数据我们可以使用write API来实现。

proto.writeI32(user.getId());
proto.writeString(user.getName());

7.4. Thrift Data Deserialization

7.4.Thrift数据反序列化

Let’s use the read APIs to deserialize the data:

让我们使用read APIs来反序列化数据。

int userId = proto.readI32();
String userName = proto.readString();

Finally, we can test the loaded data:

最后,我们可以测试加载的数据。

assertEquals(2, userId);
assertEquals("Greg", userName);

More examples can be found in our article on Apache Thrift.

更多的例子可以在我们关于Apache Thrift的文章中找到。

8. Google Protocol Buffers

8.谷歌协议缓冲区

The last approach that we’ll cover in this tutorial is Google Protocol Buffers (protobuf). It is a well-known binary data format.

我们在本教程中要介绍的最后一种方法是谷歌协议缓冲区(protobuf)。它是一种著名的二进制数据格式。

8.1. Benefits of Protocol Buffers

8.1.协议缓冲器的好处

Protocol buffers provide several benefits, including:

协议缓冲区提供了几个好处,包括。

  • It’s language and platform-neutral
  • It’s a binary transfer format, meaning the data is transmitted as binary. This improves the speed of transmission because it takes less space and bandwidth
  • Supports both backward and forward compatibility so that new versions can read old data and vice versa

8.2. Maven Dependency

8.2.Maven依赖性

Let’s start by adding the dependency for the Google protocol buffer libraries:

让我们首先添加Google协议缓冲库的依赖性。

<dependency>
    <groupId>com.google.protobuf</groupId>
    <artifactId>protobuf-java</artifactId>
    <version>3.17.3</version>
</dependency>

8.3. Defining a Protocol

8.3.定义一个协议

With our dependencies squared away, we can now define a message format:

有了我们的依赖关系,我们现在可以定义一个消息格式。

syntax = "proto3";
package protobuf;
option java_package = "com.baeldung.serialization.protocols";
option java_outer_classname = "UserProtos";
message User {
    int32 id = 1;
    string name = 2;
}

This is a protocol of a simple message of User type that has two fields – id and name, of type integer and string, respectively. Note that we’re saving it as the “user.proto” file.

这是一个User类型的简单消息的协议,它有两个字段–idname,类型分别为integerstring。注意,我们要把它保存为“user.proto”文件。

8.4. Generating a Java Code From Protobuf File

8.4.从Protobuf文件生成一个Java代码

Once we have a protobuf file, we can use the protoc compiler to generate code from it:

一旦我们有了一个protobuf文件,我们就可以使用protoc编译器来生成代码。

protoc -I=. --java_out=. user.proto

As a result, this command will generate a UserProtos.java file.

因此,这个命令将生成一个UserProtos.java文件。

After that, we can create an instance of the UserProtos class:

之后,我们可以创建一个UserProtos类的实例。

UserProtos.User user = UserProtos.User.newBuilder().setId(1234).setName("John Doe").build();

8.5. Serializing and Deserializing Protobuf

8.5.对Protobuf进行序列化和反序列化

First, we need to provide a file path to store our data:

首先,我们需要提供一个文件路径来存储我们的数据。

String filePath = "src/test/resources/protocols/usersproto";

Now, let’s save the data into a file. We can use the writeTo() method from the UserProtos class – a class we had generated from a protobuf file:

现在,让我们把数据保存到一个文件中。我们可以使用writeTo()方法,该方法来自UserProtos类–一个我们从protobuf文件生成的类。

FileOutputStream fos = new FileOutputStream(filePath);
user.writeTo(fos);

After executing this code, our object will be serialized to binary format and saved to the “usersproto” file.

执行这段代码后,我们的对象将被序列化为二进制格式并保存到”usersproto“文件中。

Oppositely, we can use the mergeFrom() method to load that data from a file and deserialize it back to a User object:

相反,我们可以使用mergeFrom() 方法从文件中加载该数据,并将其反序列化为User 对象。

UserProtos.User deserializedUser = UserProtos.User.newBuilder().mergeFrom(new FileInputStream(filePath)).build();

Finally, we can test the loaded data:

最后,我们可以测试加载的数据。

assertEquals(1234, deserializedUser.getId());
assertEquals("John Doe", deserializedUser.getName());

9. Summary

9.摘要

In this tutorial, we explored some widely used protocols for the serialization of Java objects. The choice of data serialization format for an application depends on various factors such as data complexity, need for human readability, and speed.

在本教程中,我们探讨了一些广泛使用的用于Java对象序列化的协议。一个应用程序对数据序列化格式的选择取决于各种因素,如数据的复杂性、对人类可读性的需求和速度。

Java supports built-in serialization that is easy to use.

Java支持内置的序列化,易于使用。

JSON is preferable due to readability and being schema-less. Hence, both Gson and Jackson are good options for serializing JSON data. They are simple to use and well documented. For editing data, YAML is a good fit.

JSON由于其可读性和无模式性而更受欢迎。因此,Gson和Jackson都是序列化JSON数据的好选择。它们使用简单,并且有很好的文档。对于编辑数据,YAML是一个很好的选择。

On the other hand, binary formats are faster than textual formats. When speed is important for our application, Apache Thrift and Google Protocol Buffers are great candidates for serializing data. Both are more compact and quicker than XML or JSON formats.

另一方面,二进制格式比文本格式更快。当速度对我们的应用程序很重要时,Apache Thrift和Google Protocol Buffers是序列化数据的最佳选择。两者都比XML或JSON格式更紧凑、更快速。

To sum up, there is often a trade-off between convenience and performance, and serialization proves no different. There are, of course, many other formats available for data serialization.

总而言之,在便利性和性能之间往往要进行权衡,事实证明,序列化也不例外。当然,还有许多其他可用于数据序列化的格式

As always, the full example code is over on GitHub.

一如既往,完整的示例代码在GitHub上