Skip to main content

数据的序列化与反序列化

· 6 min read

序列化(Serialization)和反序列化(Deserialization)是数据处理中的两个核心概念,特别是在分布式系统和网络通信中尤为重要。

基本概念

序列化 (Serialization)

  • 定义:将数据结构或对象状态转换为可以存储或传输的格式(通常是字节流)的过程
  • 目的:使数据能够被写入文件、通过网络传输或存入数据库

反序列化 (Deserialization)

  • 定义:将序列化后的数据(字节流)重新转换为原始数据结构或对象的过程
  • 目的:重建原始数据以便程序能够使用

为什么需要序列化

  1. 跨平台/语言交换数据:不同系统间传输对象
  2. 持久化存储:将对象保存到文件或数据库
  3. 远程通信:如 RPC 调用、消息队列传输
  4. 缓存:如 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);

其他考虑

性能与兼容性考虑

  1. 性能:二进制协议通常比文本协议更高效
  2. 兼容性
    • 向前兼容:新代码能读旧数据
    • 向后兼容:旧代码能读新数据
  3. 版本控制:设计序列化格式时应考虑未来可能的变更

安全注意事项

  1. 反序列化可能成为安全漏洞来源(如 Java 反序列化漏洞)
  2. 应对反序列化的数据进行验证
  3. 避免反序列化不可信来源的数据

理解序列化与反序列化对于设计分布式系统、数据处理管道和网络应用程序至关重要。

字节流与二进制位的概念及区别

字节流(Byte Stream)详解

字节流是计算机中最基本的数据表示和传输形式,它具有以下特性:

  1. 基本定义

    • 字节流是由连续的 8 位(bit)字节(Byte)组成的序列
    • 每个字节可以表示 0-255 的数值(2^8=256 种可能)
    • 是计算机存储和传输数据的底层形式
  2. 关键特点

    • 顺序性:数据按字节顺序排列,有明确的先后顺序
    • 连续性:在内存或存储介质上是连续分布的
    • 通用性:所有高级数据格式最终都会转换为字节流进行存储或传输
  3. 常见应用场景

    • 文件 I/O 操作(如 Java 的 InputStream/OutputStream)
    • 网络数据传输(TCP 流)
    • 内存中的缓冲区操作
    • 序列化后的对象表示

二进制位(Binary Bit)详解

二进制位是计算机中最小的数据单位:

  1. 基本定义

    • 单个 bit 只能表示 0 或 1 两种状态
    • 是构成所有数字信息的基础单元
    • 8 个 bit 组成 1 个 Byte
  2. 数据表示特点

    • 最小粒度:计算机操作的最小数据单位
    • 物理实现:在硬件层面表现为高低电压、磁性方向等物理状态
    • 组合能力:多个 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计数)

数据展示的不同层面

  1. 二进制位层面

    • 纯粹的 0 和 1 序列
    • 如:01101000 01100101 01101100 01101100 01101111
  2. 字节流层面

    • 按字节组织的十六进制表示
    • 如:68 65 6C 6C 6F ("hello"的 ASCII 编码)
  3. 高级数据表示

    • 解码后的可读形式
    • 如字符串"hello"、数字 12345、结构体对象等

为什么需要区分这两个概念

  1. 编程抽象:字节流是对二进制位的更高层次抽象
  2. 效率考量:现代计算机体系结构更适合字节(或字)级别的操作
  3. 可操作性:直接操作 bit 过于底层,大多数应用不需要这种控制粒度
  4. 标准化:字节作为标准数据单元便于跨系统交换数据

理解字节流和二进制位的区别有助于更好地处理数据存储、网络通信和性能优化等问题。

Resources