🔥个人主页: Milestone-里程碑
❄️个人专栏: <<力扣hot100>> <<C++>><<Linux>>
🌟心向往之行必能至
目录
[1. Protobuf:追求 "快" 和 "小"](#1. Protobuf:追求 “快” 和 “小”)
[2. JSON:追求 "简单" 和 "通用"](#2. JSON:追求 “简单” 和 “通用”)
[3. XML:追求 "严谨" 和 "兼容"](#3. XML:追求 “严谨” 和 “兼容”)
[一、方法 1:用 protoc 工具解析二进制数据(最常用)](#一、方法 1:用 protoc 工具解析二进制数据(最常用))
[二、方法 2:在代码中打印字段值(调试代码用)](#二、方法 2:在代码中打印字段值(调试代码用))
[C++ 代码示例(小白直接抄)](#C++ 代码示例(小白直接抄))
[三、方法 3:用在线工具解析(适合临时调试)](#三、方法 3:用在线工具解析(适合临时调试))
在数据传输和存储中,Protobuf、JSON、XML 是最常用的三种格式。很多小白会纠结:我该用哪个?这篇用 "大白话 + 表格对比",帮你理清它们的优缺点和适用场景,不用懂复杂原理,直接对号入座。
一、先搞懂:三种格式分别是啥?(小白视角)
- JSON :最常用的 "文本格式",用
{}、[]组织数据,比如{"name":"张三","age":25},人类能直接看懂; - XML :早期常用的 "文本格式",用标签组织数据,比如
<name>张三</name><age>25</age>,结构更严谨,但标签冗余; - Protobuf:"二进制格式",数据被压缩成二进制包,人类看不懂,必须用工具解析,但体积小、速度快。
二、核心对比:一张表看懂区别
表格
| 对比维度 | Protobuf | JSON | XML |
|---|---|---|---|
| 可读性 | 差(二进制,需解析) | 好(文本,直接看懂) | 好(文本,标签清晰) |
| 序列化后体积 | 最小(约 JSON 的 1/2) | 中等(有冗余符号) | 最大(标签冗余多) |
| 编解码速度 | 最快(JSON 的 2-4 倍) | 中等 | 最慢 |
| 版本兼容性 | 强(新增 / 删除字段不影响) | 中等(需兼容字段) | 中等(需兼容标签) |
| 语言支持 | 支持多语言(需编译) | 支持所有语言(原生解析) | 支持所有语言(原生解析) |
| 学习成本 | 中等(需写 .proto 文件) | 低(语法简单) | 高(标签规则复杂) |
| 适用场景 | 后台通信、跨语言传输 | 前后端交互、配置文件 | 传统系统、配置文件 |
三、大白话解读:各自的优缺点
1. Protobuf:追求 "快" 和 "小"
- 优点:体积最小、速度最快、版本兼容性最强,适合需要高效传输的场景;
- 缺点:人类看不懂(调试时需要解析工具)、需要写 .proto 文件和编译,学习成本比 JSON 高。
2. JSON:追求 "简单" 和 "通用"
- 优点:语法简单、人类能直接看懂(调试方便)、所有语言都原生支持(不用编译);
- 缺点:体积比 Protobuf 大、速度比 Protobuf 慢,不适合对性能要求极高的场景。
3. XML:追求 "严谨" 和 "兼容"
- 优点:结构严谨、标签语义清晰,适合需要严格格式的传统系统;
- 缺点:体积最大、速度最慢、标签冗余多,现在除了老系统,很少用在新项目中。
四、小白该怎么选?(直接对号入座)
- 如果你是做 APP 后台、游戏服务器、跨语言传输(比如 Python 传数据给 C++):选 Protobuf(省流量、速度快、兼容好);
- 如果你是做网站、小程序(前后端交互)、简单的配置文件:选 JSON(简单、调试方便、前端原生支持);
- 如果你是维护老系统,或者需要严格的格式校验:选 XML(老系统兼容、结构严谨)。
五、实战场景举例
- 场景 1:手机 APP 向后台发送用户登录信息(账号、密码)------ 用 JSON(简单、调试方便,流量消耗不大);
- 场景 2:游戏中实时同步玩家位置、血量(需要快速传输)------ 用 Protobuf(速度快、省流量,避免卡顿);
- 场景 3:Python 爬虫爬取数据,传给 C++ 程序分析(跨语言)------ 用 Protobuf(跨语言支持好,解析快);
- 场景 4:网站的配置文件(比如数据库地址、端口)------ 用 JSON(简单易改,人类能直接看懂)。
六、总结:不用纠结,按需求选
- 追求性能(快、小)、跨语言、版本兼容:选 Protobuf;
- 追求简单、通用、前后端交互:选 JSON;
- 老系统兼容、严格格式要求:选 XML。
对于大多数小白来说,先学 JSON 足够应对日常开发;如果后续涉及后台通信、跨语言传输,再学 Protobuf 就行 ------ 两者并不冲突,很多项目会同时用(比如前后端用 JSON,后台服务之间用 Protobuf)。
Protobuf 打包后的数据是二进制的,人类看不懂,调试时很不方便 ------ 比如想确认数据有没有打包成功,或者为什么旧程序解析不了新数据,这时候就需要调试技巧。
这篇教你 3 个小白能快速上手的调试方法,不用复杂工具,跟着做就能查看二进制数据的内容。
一、方法 1:用 protoc 工具解析二进制数据(最常用)
Protobuf 自带 protoc 工具,能把二进制数据解析成人类能看懂的文本格式。适合调试时快速查看数据内容。
操作步骤(小白直接抄)
-
准备好你的
.proto文件(比如contacts.proto)和二进制数据文件(比如data.bin,里面存的是打包后的二进制数据); -
打开 cmd / 终端,进入这两个文件所在的文件夹;
-
执行解析命令: bash
运行
# 通用格式:protoc --decode=包名.消息体名 你的.proto文件 < 二进制数据文件 > 输出文本文件 protoc --decode=contacts.PeopleInfo contacts.proto < data.bin > output.txt
命令解释(不用记)
--decode=contacts.PeopleInfo:指定要解析的消息体(contacts是包名,PeopleInfo是消息体名);contacts.proto:你的规则文件(必须和打包时用的一致);< data.bin:读取二进制数据文件;> output.txt:把解析后的文本输出到output.txt文件。
示例:解析联系人数据
如果 data.bin 里是 PeopleInfo 类型的二进制数据,解析后的 output.txt 内容会是:
plaintext
name: "张三"
age: 25
phone: "13111111111"
phone: "010-88888888"
is_important: true
weixin: "zhangsan_123"
remark {
key: "日程"
value: "10月1日出游"
}
remark {
key: "标签"
value: "重要客户"
}
extra {
[type.googleapis.com/contacts.Address] {
home: "陕西省西安市"
work: "陕西省西安市高新区"
}
}
这样就能清楚看到二进制数据里的所有字段,确认打包是否正确。
二、方法 2:在代码中打印字段值(调试代码用)
如果是在开发过程中调试,最直接的方法是在代码中打印每个字段的值,确认数据是否正确设置和解析。
C++ 代码示例(小白直接抄)
cpp
运行
// 打包前打印设置的字段
cout << "打包前的字段值:" << endl;
cout << "姓名:" << people.name() << endl;
cout << "年龄:" << people.age() << endl;
for (int i = 0; i < people.phone_size(); ++i) {
cout << "电话" << i+1 << ":" << people.phone(i) << endl;
}
// 拆包后打印解析的字段
cout << "\n拆包后的字段值:" << endl;
cout << "姓名:" << new_people.name() << endl;
cout << "年龄:" << new_people.age() << endl;
这种方法适合调试代码逻辑,确认字段是否正确赋值、解析。
三、方法 3:用在线工具解析(适合临时调试)
如果没有 protoc 工具,或者想快速解析少量数据,可以用在线工具。适合小白临时调试,不用安装软件。
操作步骤
- 打开在线解析工具(推荐:https://protogen.marcgravell.com/decode);
- 粘贴你的
.proto文件内容(比如contacts.proto的代码); - 上传二进制数据文件(或粘贴二进制数据的 Base64 编码);
- 点击解析,就能看到人类能看懂的文本格式。
注意事项
- 在线工具适合临时调试,不要上传敏感数据(比如用户密码、身份证号);
- 确保上传的
.proto文件和打包时用的完全一致,否则解析会出错。
四、常见问题排查(小白必看)
-
解析二进制数据时提示 "unknown field"(未知字段):
- 原因:解析用的
.proto文件和打包时用的不一致(比如打包时加了新字段,解析时用的是旧.proto); - 解决:用和打包时一致的
.proto文件重新解析。
- 原因:解析用的
-
解析时提示 "invalid wire type"(无效的编码类型):
- 原因:二进制数据损坏,或者解析的消息体类型不对(比如打包的是
PeopleInfo,解析时指定的是ContactsList); - 解决:检查二进制数据是否完整,确认解析时指定的消息体类型和打包时一致。
- 原因:二进制数据损坏,或者解析的消息体类型不对(比如打包的是
-
代码中能设置字段,但打包后解析不到:
- 原因:字段编号重复,或者字段类型不兼容;
- 解决:检查
.proto文件的字段编号是否重复,确认字段类型是兼容的(比如不要把 string 改成 int32)。
五、总结:调试技巧的使用场景
- 快速查看二进制数据内容:用方法 1(protoc 工具);
- 调试代码逻辑,确认字段赋值 / 解析:用方法 2(代码中打印);
- 临时调试,没有 protoc 工具:用方法 3(在线工具)。
掌握这 3 种方法,小白也能轻松排查 Protobuf 的常见问题,不用再对着二进制数据 "两眼一抹黑"。
下一篇,我们总结 Protobuf 的核心知识点和学习路径,帮你快速巩固所学内容,从入门到实战。