MessagePack 比 JSON 更紧凑的序列化

FreeGuideOnline 最新 2026-07-11

json {"name": "Alice", "age": 30, "email": "alice@example.com"}


**JSON 文本格式**(68 字节):

{"name":"Alice","age":30,"email":"alice@example.com"}


**MessagePack 二进制格式**(约 48 字节,具体取决于实现):

83 a4 6e 61 6d 65 a5 41 6c 69 63 65 a3 61 67 65 1e a5 65 6d 61 69 6c af 61 6c 69 63 65 40 65 78 61 6d 70 6c 65 2e 63 6f 6d

*说明:十六进制表示。`83` 表示一个包含 3 个键值对的 map,`a4` 表示长度为 4 的字符串 "name",`a5` 表示 "Alice",`a3` 表示 "age",`1e` 是整数 30,`af` 是长度为 15 的字符串等。*

### 紧凑性分析
- JSON 使用引号、冒号、逗号、花括号等字符,键名 "name"、"age" 在每条记录中都需要完整写出。
- MessagePack 使用前缀字节标记数据类型和长度:
  - 小整数(0-127)直接用一个字节存储,如 `30` 就是 `0x1e`。
  - 字符串前缀 `0xa0-0xbf` 标记短字符串长度(最多 31 字节),后面紧跟字节内容,无需引号。
  - 数组、Map 等也用类型前缀表示,而不是 `[` `{` 等字符。
- 键名 "name"、"age" 在二进制中仍然出现,但通过长度前缀减少了分隔符,整体更加紧凑。在大多数实际数据中,MessagePack 比 JSON 小 30%~50%。

## MessagePack 的核心优势
- **体积更小**:二进制编码消除了大量冗余字符,尤其适合网络传输和存储。
- **解析更快**:二进制格式不需要进行复杂的文本解析,类型信息直接编码在前缀字节中,可以实现高效的零拷贝或接近零拷贝的解析。
- **跨语言支持**:官方和社区提供了超过 50 种语言的实现,包括 Python、JavaScript/TypeScript、Java、Go、C++、Rust 等,无缝替代 JSON。
- **保留 JSON 兼容性**:数据模型与 JSON 高度一致(支持数字、字符串、布尔、数组、map/null),可以无损地将 JSON 转换为 MessagePack 再转回。
- **支持流式处理**:可以在不完整数据到达时逐步解析,适用于消息队列、RPC 等场景。

## 快速入门:Python 示例
我们使用官方 `msgpack` 库来体验 MessagePack 的紧凑性。

### 安装
```bash
pip install msgpack

序列化与反序列化

import msgpack
import json

# 原始数据
data = {"name": "Alice", "age": 30, "email": "alice@example.com"}

# 序列化为 MessagePack 字节
packed = msgpack.packb(data)
print("MessagePack 大小:", len(packed))   # 约 48 字节
print("二进制数据:", packed.hex())

# 从 MessagePack 反序列化
unpacked = msgpack.unpackb(packed)
print("反序列化结果:", unpacked)

# 与 JSON 对比
json_str = json.dumps(data)
print("JSON 大小:", len(json_str))        # 68 字节
print("JSON 文本:", json_str)

输出示例:

MessagePack 大小: 48
二进制数据: 83a46e616d65a5416c696365a36167651ea5656d61696caf616c696365406578616d706c652e636f6d
反序列化结果: {'name': 'Alice', 'age': 30, 'email': 'alice@example.com'}
JSON 大小: 68
JSON 文本: {"name": "Alice", "age": 30, "email": "alice@example.com"}

处理复杂数据

MessagePack 支持嵌套结构、数组、二进制数据等。

import msgpack

# 包含二进制数据(图像字节流等)
image_data = b'\xFF\xD8\xFF\xE0...'  # 模拟二进制
payload = {
    "id": 1001,
    "sensors": [23.5, 45.1, 18.3],
    "metadata": {"version": 2, "compressed": True},
    "raw": image_data
}

packed = msgpack.packb(payload)
unpacked = msgpack.unpackb(packed)
print(unpacked["raw"] == image_data)  # True