数据的序列化与反序列化
· 6 min read
序列化(Serialization)和反序列化(Deserialization)是数据处理中的两个核心概念,特别是在分布式系统和网络通信中尤为重要。
基本概念
序列化 (Serialization)
- 定义:将数据结构或对象状态转换为可以存储或传输的格式(通常是字节流)的过程
- 目的:使数据能够被写入文件、通过网络传输或存入数据库
反序列化 (Deserialization)
- 定义:将序列化后的数据(字节流)重新转换为原始数据结构或对象的过程
- 目的:重建原始数据以便程序能够使用
为什么需要序列化
- 跨平台/语言交换数据:不同系统间传输对象
- 持久化存储:将对象保存到文件或数据库
- 远程通信:如 RPC 调用、消息队列传输
- 缓存:如 Redis 等缓存系统中存储复杂对象
常见序列化格式
1. 二进制格式
- Protocol Buffers (Google 开发,高效紧凑)
- Thrift (Facebook 开发,跨语言支持好)
- Java 原生序列化 (Java 特有)
- Avro (Hadoop 生态常用)
2. 文本格式
- JSON (最流行的轻量级格式)
- XML (较重量级,但结构严谨)
- YAML (人类可读性更好)
- CSV (表格数据常用)
序列化应用
Kafka 中的序列化应用
在 Kafka 中,生产者和消费者需要使用序列化器(Serializer)和反序列化器(Deserializer):
// 生产者配置序列化器
props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
props.put("value.serializer", "org.apache.kafka.common.serialization.ByteArraySerializer");
// 消费者配置反序列化器
props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
props.put("value.deserializer", "org.apache.kafka.common.serialization.ByteArrayDeserializer");
序列化过程示例(JSON)
// 序列化(对象 → JSON字符串)
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(myObject);
// 反序列化(JSON字符串 → 对象)
MyClass obj = mapper.readValue(json, MyClass.class);
其他考虑
性能与兼容性考虑
- 性能:二进制协议通常比文本协议更高效
- 兼容性:
- 向前兼容:新代码能读旧数据
- 向后兼容:旧代码能读新数据
- 版本控制:设计序列化格式时应考虑未来可能的变更
安全注意事项
- 反序列化可能成为安全漏洞来源(如 Java 反序列化漏洞)
- 应对反序列化的数据进行验证
- 避免反序列化不可信来源的数据
理解序列化与反序列化对于设计分布式系统、数据处理管道和网络应用程序至关重要。
字节流与二进制位的概念及区别
字节流(Byte Stream)详解
字节流是计算机中最基本的数据表示和传输形式,它具有以下特性:
-
基本定义:
- 字节流是由连续的 8 位(bit)字节(Byte)组成的序列
- 每个字节可以表示 0-255 的数值(2^8=256 种可能)
- 是计算机存储和传输数据的底层形式
-
关键特点:
- 顺序性:数据按字节顺序排列,有明确的先后顺序
- 连续性:在内存或存储介质上是连续分布的
- 通用性:所有高级数据格式最终都会转换为字节流进行存储或传输
-
常见应用场景:
- 文件 I/O 操作(如 Java 的 InputStream/OutputStream)
- 网络数据传输(TCP 流)
- 内存中的缓冲区操作
- 序列化后的对象表示
二进制位(Binary Bit)详解
二进制位是计算机中最小的数据单位:
-
基本定义:
- 单个 bit 只能表示 0 或 1 两种状态
- 是构成所有数字信息的基础单元
- 8 个 bit 组成 1 个 Byte
-
数据表示特点:
- 最小粒度:计算机操作的最小数据单位
- 物理实现:在硬件层面表现为高低电压、磁性方向等物理状态
- 组合能力:多个 bit 组合可表示更复杂的数据
字节流与二进制位的区别
特性 | 字节流(Byte Stream) | 二进制位(Binary Bit) |
---|---|---|
组成单元 | 由多个字节(8bit)组成 | 单个 0 或 1 |
数据粒度 | 中等粒度(面向应用层) | 最小粒度(面向硬件层) |
人类可读性 | 通常不可直接阅读(需解码) | 完全不可直接阅读 |
操作级别 | 编程中常操作的对象(如文件流、网络流) | 很少直接操作,多由硬件和底层系统处理 |
表示能力 | 可直接表示 ASCII 字符、部分二进制数据 | 只能表示开/关、真/假等二元状态 |
存储效率 | 已包含一定的组织结构和冗余(每个字节 8bit 固定) | 绝对紧凑,无任何冗余 |
实际示例对比
字节流示例
字母"A"的表示:
- ASCII 编码:单个字节
01000001
(十六进制 0x41) - UTF-8 编码:单个字节
01000001
- 文件中的表现:实际存储的就是这个 8 位二进制序列
二进制位操作示例
// C语言中的位操作
unsigned char byte = 0x41; // 01000001
int thirdBit = (byte >> 2) & 1; // 提取第3位(从0计数)
数据展示的不同层面
-
二进制位层面:
- 纯粹的 0 和 1 序列
- 如:
01101000 01100101 01101100 01101100 01101111
-
字节流层面:
- 按字节组织的十六进制表示
- 如:
68 65 6C 6C 6F
("hello"的 ASCII 编码)
-
高级数据表示:
- 解码后的可读形式
- 如字符串"hello"、数字 12345、结构体对象等
为什么需要区分这两个概念
- 编程抽象:字节流是对二进制位的更高层次抽象
- 效率考量:现代计算机体系结构更适合字节(或字)级别的操作
- 可操作性:直接操作 bit 过于底层,大多数应用不需要这种控制粒度
- 标准化:字节作为标准数据单元便于跨系统交换数据
理解字节流和二进制位的区别有助于更好地处理数据存储、网络通信和性能优化等问题。