嵌入式开发必备!轻量级JSON库tiny-json详解,内存紧张场景救星来了
嵌入式开发必备!轻量级JSON库tiny-json详解,内存紧张场景救星来了
在嵌入式开发中,你是不是常遇到这样的困境:设备内存就那么点儿,想用上JSON这种通用数据格式,却被主流库的“臃肿”劝退?
别急,今天给大家安利一款专为资源受限场景设计的轻量级JSON解析/生成库——tiny-json,让你在MCU、物联网设备上轻松玩转JSON!
一、什么是tiny-json?
简单说,“tiny-json”是一款轻量级JSON解析库,核心目标就三个字:小、省、快。
它专为嵌入式系统、物联网设备、小型客户端等资源紧张的场景而生,完美避开了主流JSON库(比如CJSON、nlohmann/json)因功能全面带来的体积冗余问题。其官方开源地址为:https://github.com/rafagafe/tiny-json ,开发者可以在该仓库获取源码、示例及相关文档。
二、tiny-json的核心优势:为什么适合嵌入式开发?
用过主流JSON库的开发者都知道,功能全是全,但在嵌入式设备上简直“水土不服”。而tiny-json的优势,恰恰戳中了资源受限场景的痛点:
-
体积极小
源码通常就1-2个文件(.h+.c),代码量精简,编译后占用ROM通常在10KB以内,对存储敏感的嵌入式设备太友好了!
-
内存友好到极致
不依赖malloc/new等动态内存分配,靠用户提供的静态缓冲区操作,从根源上避免内存泄漏;不搞复杂中间对象,直接基于原始JSON字符串解析,RAM占用低至几十到几百字节,MCU表示“毫无压力”。
-
功能聚焦核心
只实现JSON必备语法(对象、数组、字符串、数字、布尔值、null),像注释、特殊编码、格式化输出这些“花活”一概没有,把复杂度压到最低。
-
跨平台无依赖
纯C实现,不挑操作系统和硬件,不管是STM32、Arduino,还是Linux/macOS小型程序,移植起来顺顺当当。
-
无递归设计
解析过程不使用递归,避免了在资源有限的嵌入式设备上可能出现的栈溢出问题,运行更稳定。
-
支持嵌套结构
虽然轻量,但对JSON中的嵌套对象和数组没有层级限制,能满足复杂数据结构的解析需求。
三、和其他库比,tiny-json强在哪?
给大家做个直观对比:
| 库名 | 优势 | 短板 | 适合场景 |
|---|---|---|---|
| cJSON | API友好,功能全面 | 动态分配多,内存占用高 | 资源较充足的嵌入式设备 |
| tiny-json | 静态分配,零拷贝,超轻量,无递归 | 功能精简,无扩展特性 | 内存紧张的MCU、物联网设备 |
简单说,如果你在开发资源受限的小设备,tiny-json几乎是最优解!
四、实战演示:tiny-json怎么用?
光说不练假把式,我们通过具体例程,看看tiny-json如何解析JSON数据。
例程1:基础解析(获取简单字段)
假设我们有一段包含姓名和年龄的JSON字符串,解析步骤如下:
步骤1:定义JSON字符串和静态内存池
enum { MAX_FIELDS = 4 };
json_t pool[ MAX_FIELDS ]; // 静态内存池,存储JSON节点
char str[] = "{ \\"name\\": \\"peter\\", \\"age\\": 32 }";
步骤2:解析JSON字符串
json_t const* parent = json_create(str, pool, MAX_FIELDS);
if (parent == NULL) return EXIT_FAILURE; // 解析失败处理
步骤3:提取字符串类型字段(姓名)
json_t const* namefield = json_getProperty(parent, "name");
if (namefield == NULL || json_getType(namefield) != JSON_TEXT) {
// 字段不存在或类型错误处理
}
char const* namevalue = json_getValue(namefield); // 获取值(字符串)
printf("姓名:%s\\n", namevalue); // 输出:peter
步骤4:提取数字类型字段(年龄)
json_t const* agefield = json_getProperty(parent, "age");
if (agefield == NULL || json_getType(agefield) != JSON_INTEGER) {
// 字段不存在或类型错误处理
}
int64_t agevalue = json_getInteger(agefield); // 获取值(整数)
printf("年龄:%lld\\n", agevalue); // 输出:32
例程2:解析嵌套对象和数组
对于包含嵌套对象(如地址)和数组(如电话列表)的复杂JSON,解析方式如下(核心步骤):
步骤1:定义复杂JSON字符串
char str[] = "{\\n"
"\\t\\"firstName\\": \\"Bidhan\\",\\n"
"\\t\\"lastName\\": \\"Chatterjee\\",\\n"
"\\t\\"age\\": 40,\\n"
"\\t\\"address\\": {\\n"
"\\t\\t\\"streetAddress\\": \\"144 J B Hazra Road\\",\\n"
"\\t\\t\\"city\\": \\"Burdwan\\"\\n"
"\\t},\\n"
"\\t\\"phoneList\\": [\\n"
"\\t\\t{ \\"type\\": \\"personal\\", \\"number\\": \\"09832209761\\" },\\n"
"\\t\\t{ \\"type\\": \\"fax\\", \\"number\\": \\"91-342-2567692\\" }\\n"
"\\t]\\n"
"}\\n";
步骤2:解析嵌套对象(地址)
json_t const* address = json_getProperty(json, "address");
if (address && json_getType(address) == JSON_OBJ) {
char const* city = json_getPropertyValue(address, "city");
printf("城市:%s\\n", city); // 输出:Burdwan
}
步骤3:遍历数组(电话列表)
json_t const* phoneList = json_getProperty(json, "phoneList");
if (phoneList && json_getType(phoneList) == JSON_ARRAY) {
json_t const* phone;
// 用json_getChild(首个元素)和json_getSibling(下一个元素)遍历
for (phone = json_getChild(phoneList); phone != 0; phone = json_getSibling(phone)) {
if (json_getType(phone) == JSON_OBJ) {
char const* number = json_getPropertyValue(phone, "number");
printf("电话号码:%s\\n", number);
}
}
}
运行结果
最终程序会输出解析后的信息:
姓名:peter
年龄:32
城市:Burdwan
电话号码:09832209761
电话号码:91-342-2567692
五、tiny-json的API详解
tiny-json的API简洁直观,核心接口如下:
- json_create():解析JSON字符串,参数为JSON字符串、静态内存池、最大字段数,返回根节点。
- json_getProperty():根据字段名获取子节点,用于对象类型。
- json_getType():获取节点类型(JSON_OBJ、JSON_ARRAY、JSON_TEXT等)。
- json_getValue():获取节点的字符串形式值(所有类型通用)。
- json_getInteger():获取整数类型节点的值(int64_t)。
- json_getChild():获取数组的第一个元素节点。
- json_getSibling():获取当前节点的下一个同级节点(用于数组遍历)。
六、总结:tiny-json为什么值得用?
通过以上内容可以看出,tiny-json的设计非常贴合嵌入式开发需求:
- 用静态内存池避免动态分配,减少内存碎片和泄漏风险;
- 接口简洁直观,专注于“解析JSON”核心需求,降低学习和使用成本;
- 体积和内存占用极小,在资源紧张的设备上也能流畅运行;
- 支持嵌套结构和数组,满足多数嵌入式场景的数据解析需求。
如果你正在开发MCU、物联网设备等资源受限的项目,又需要处理JSON数据,不妨去其官方仓库(https://github.com/rafagafe/tiny-json )看看,tiny-json绝对是一个值得尝试的轻量之选!
更多推荐
所有评论(0)