ProtoBuf
1. 序列化概念
1.1 序列化和反序列化
序列化是将数据结构或对象转换为可以存储或传输的格式(通常是字节序列)的过程。 其目的是将复杂的数据结构转化为一种便于存储、传输或在不同系统之间交换的形式。
例如,在网络通信中,要将内存中的一个对象通过网络发送给另一台计算机,就需要先将这个对象序列化为字节流。
反序列化则是序列化的逆过程,它将序列化后的数据(如字节流)重新转换回原始的数据结构或对象。
比如说,当另一台计算机接收到序列化后的字节流数据后,需要通过反序列化将其还原为原始的对象,以便进行后续的处理和操作。
假设我们有一个包含学生姓名、年龄和成绩的对象。序列化可能会将这个对象转换为一个特定格式的字符串,如 {“name”:“张三”,“age”:20,“score”:90} 。而反序列化就是把接收到的这样的字符串重新转换回包含姓名、年龄和成绩的学生对象。
总结:
序列化:把对象转换为字节序列的过程 称为对象的序列化。
反序列化:把字节序列恢复为对象的过程 称为对象的反序列化。
1.2 为什么需要序列化和反序列化
数据存储:
当需要将数据持久化保存到文件或数据库中时,内存中的对象结构不能直接进行存储。通过序列化将对象转换为一种适合存储的格式,如二进制、JSON 或 XML 等,以便后续能够从存储介质中读取并反序列化还原为对象进行使用。
例如,一个电商网站需要定期将用户的购物车信息保存到数据库中,就需要先对购物车对象进行序列化。
网络通信:
网络只能传输字节流,无法直接传输对象。序列化将对象转换为字节流在网络中传输,接收方再进行反序列化得到原始对象,实现不同节点之间的数据交换。
比如,在分布式系统中,一个客户端发送请求给服务器,请求中的对象需要序列化后才能通过网络发送给服务器,服务器接收后反序列化进行处理。
跨语言和平台:
不同的编程语言和平台对数据的表示和处理方式可能不同。序列化可以使用一种通用的格式(如 Protocol Buffers、JSON 等),使得数据能够在不同语言和平台之间进行传输和转换。
例如,一个用 Java 编写的服务需要与用 Python 编写的服务进行通信,通过序列化和反序列化可以实现数据的共享和交互。
提高性能:
某些序列化格式经过优化,能够更高效地表示数据,减少存储空间和传输带宽的消耗。
比如,在高并发的网络环境中,使用高效的序列化方式可以显著提高系统的性能和响应速度。
版本控制和兼容性:
当对象的结构发生变化时,通过合理设计的序列化和反序列化机制,可以处理不同版本的数据,保证一定的兼容性。
假设一个系统升级,对象新增了一些字段,旧版本序列化的数据在新版本中进行反序列化时,可以根据特定规则进行处理,避免数据丢失或错误。
一般来说这两个地方需要序列化较多:
存储数据:当您想要将内存中的对象状态保存至一个文件中或者存到数据库中时。
网络传输:网络直接传输数据,但无法直接传输对象,所以需要在传输前序列化,传输完成后反序列化成对象。例如我们之前学习过的 socket 编程中发送与接收数据。
1.3 如何实现序列化
(1)使用编程语言提供的内置序列化机制:
许多编程语言都内置了序列化的功能。 例如,Java 中的 java.io.Serializable 接口,通过实现这个接口,对象可以被 Java 的序列化机制处理。
import java.io.Serializable;
public class Student implements Serializable {
private String name;
private int age;
// 构造函数、getter 和 setter 方法
}
(2)使用特定的序列化库或框架:
如 Protocol Buffers、JSON 库(如 Jackson、Gson 等)、XML 序列化库(如 JAXB)。
使用 Protocol Buffers 时,需要定义 .proto 文件来描述数据结构,然后使用相关工具生成代码进行序列化和反序列化操作。
Protocol Buffers(Protobuf)为例:
// --- protobuf
syntax = "proto3"