当前位置: 首页 > news >正文

Qt---JSON处理体系

Qt框架提供了一套完整的JSON处理工具集,其中QJsonObject、QJsonArray、QJsonDocument和QJsonValue是核心组件。这些类共同构成了JSON数据的创建、解析、修改和序列化能力,广泛应用于网络数据交换、配置文件处理、数据持久化等场景。

一、Qt JSON体系的整体架构

Qt的JSON处理模块(Qt Core内置)采用分层设计,各组件职责明确:

  • QJsonValue:基础值类型容器,封装JSON支持的所有原始类型(字符串、数字、布尔等)及复合类型(对象、数组),是其他类交互的基础;
  • QJsonObject:对应JSON对象({}),管理无序键值对集合(键为字符串,值为QJsonValue);
  • QJsonArray:对应JSON数组([]),管理有序QJsonValue列表;
  • QJsonDocument:顶层文档容器,负责JSON数据的解析(从字符串/二进制到对象/数组)和序列化(从对象/数组到字符串/二进制)。

四者的关系可概括为:QJsonDocument包含QJsonObject或QJsonArray,后两者由QJsonValue组成,而QJsonValue可嵌套其他复合类型,形成任意深度的JSON结构。

二、QJsonValue:JSON值的基础容器

QJsonValue是Qt JSON体系的"原子",它封装了JSON规范定义的所有值类型,是QJsonObject和QJsonArray的基本组成单元。

1. 支持的类型与类型判断

QJsonValue支持7种JSON值类型,通过Type枚举定义:

  • Null:空值(对应JSON的null);
  • Bool:布尔值(true/false);
  • Double:数值(JSON不区分整数和浮点数,统一用double存储);
  • String:字符串(UTF-8编码);
  • Array:数组(嵌套QJsonArray);
  • Object:对象(嵌套QJsonObject);
  • Undefined:未定义(仅用于错误场景)。

通过类型判断方法可检查当前值的类型:

QJsonValue value = ...;
if (value.isNull())        { /* 处理null */ }
else if (value.isBool())   { /* 处理布尔值 */ }
else if (value.isDouble()) { /* 处理数值 */ }
else if (value.isString()) { /* 处理字符串 */ }
else if (value.isArray())  { /* 处理数组 */ }
else if (value.isObject()) { /* 处理对象 */ }
2. 值的获取与转换

QJsonValue提供类型安全的取值方法,若类型不匹配,返回默认值(如toInt()对非数字值返回0):

// 布尔值
bool b = value.toBool();                  // 类型不匹配返回false
bool bOk;
bool b2 = value.toBool(&bOk);             // bOk指示转换是否成功// 数值(自动转换为对应类型)
double d = value.toDouble();              // 基础数值获取
int i = value.toInt();                    // 截断为整数
qint64 ll = value.toInteger();            // Qt 5.14+,支持大整数// 字符串
QString s = value.toString();             // 非字符串类型返回空字符串
QString s2 = value.toString("default");   // 转换失败时返回默认值// 复合类型(返回引用,需先判断类型)
if (value.isArray()) {QJsonArray arr = value.toArray();     // 转换为数组
}
if (value.isObject()) {QJsonObject obj = value.toObject();   // 转换为对象
}

注意:JSON数值在Qt中统一以double存储,对于超出double精度的大整数(如超过53位的整数),可能导致精度丢失。Qt 5.14+新增toInteger()方法,通过内部判断处理大整数场景。

3. 构造与修改

QJsonValue支持隐式构造,可直接用原始类型初始化:

QJsonValue v1;                          // 默认构造为Null
QJsonValue v2(true);                    // Bool类型
QJsonValue v3(3.14);                    // Double类型
QJsonValue v4("hello");                 // String类型
QJsonValue v5(QJsonArray{1, 2, 3});     // Array类型
QJsonValue v6(QJsonObject{{"key", "val"}}); // Object类型

通过setValue()可修改已有QJsonValue的值:

QJsonValue value;
value.setValue(42);          // 改为Double类型
value.setValue("new str");   // 改为String类型

三、QJsonObject:JSON对象的键值对管理

QJsonObject对应JSON规范中的对象({key:value, ...}),是无序键值对的集合,键为唯一字符串,值为QJsonValue。

1. 构造与初始化

QJsonObject可通过多种方式创建:

// 1. 空对象构造
QJsonObject obj1;// 2. 初始化列表构造(C++11+)
QJsonObject obj2{{"name", "Qt"},{"version", 6.5},{"stable", true}
};// 3. 从QVariantMap转换(键为QString,值为QVariant支持的类型)
QVariantMap varMap;
varMap["id"] = 1001;
varMap["active"] = true;
QJsonObject obj3 = QJsonObject::fromVariantMap(varMap);
2. 键值对的添加、修改与删除

QJsonObject提供丰富的接口管理键值对:

QJsonObject obj;// 添加/修改键值对(operator[])
obj["name"] = "Qt JSON";               // 新增字符串键值对
obj["version"] = 6.5;                  // 新增数值键值对
obj["features"] = QJsonArray{"fast", "safe"}; // 新增数组值// 插入键值对(insert(),返回迭代器)
auto it = obj.insert("stable", true);  // 插入布尔值// 删除键值对
obj.remove("version");                 // 通过键删除
obj.erase(it);                         // 通过迭代器删除// 检查键是否存在
bool hasName = obj.contains("name");   // true

注意:键是唯一的,重复插入相同键会覆盖原有值;键的比较是大小写敏感的("Name""name"视为不同键)。

3. 键与值的访问

访问键值对的常用方法:

// 获取所有键(返回QStringList,无序)
QStringList keys = obj.keys();// 通过键获取值(value()返回QJsonValue,不存在则返回Null)
QJsonValue nameVal = obj.value("name");
QJsonValue versionVal = obj["version"]; // operator[]等价于value()// 安全获取嵌套值(避免链式调用中的空指针)
QJsonValue nestedVal = obj["parent"]["child"]; // 若parent不存在,返回Null// 获取值的原始类型(需先判断类型)
if (nameVal.isString()) {QString name = nameVal.toString();
}
4. 遍历与迭代

QJsonObject支持STL风格和Java风格两种迭代方式:

// 1. STL风格迭代(只读)
for (auto it = obj.constBegin(); it != obj.constEnd(); ++it) {qDebug() << "键:" << it.key() << ",值:" << it.value();
}// 2. STL风格迭代(可修改)
for (auto it = obj.begin(); it != obj.end(); ++it) {if (it.key() == "version") {it.value() = 6.6; // 修改值}
}// 3. Java风格迭代(QJsonObjectIterator)
QJsonObjectIterator it(obj);
while (it.hasNext()) {it.next();qDebug() << it.key() << ":" << it.value();
}
5. 与QVariantMap的转换

QJsonObject与QVariantMap(Qt的通用键值对容器)可双向转换,便于与Qt其他模块(如QSettings)交互:

// QJsonObject → QVariantMap
QVariantMap varMap = obj.toVariantMap();// QVariantMap → QJsonObject(仅支持QVariant可转换为QJsonValue的类型)
QJsonObject objFromMap = QJsonObject::fromVariantMap(varMap);

转换限制:QVariant中的部分类型(如QColor、QDateTime)无法直接转换为JSON值,需手动序列化(如转为字符串)后再存储。

四、QJsonArray:JSON数组的有序列表管理

QJsonArray对应JSON规范中的数组([value1, value2, ...]),是有序QJsonValue的列表,支持重复元素和嵌套结构。

1. 构造与初始化

QJsonArray的创建方式与QJsonObject类似:

// 1. 空数组构造
QJsonArray arr1;// 2. 初始化列表构造
QJsonArray arr2{1, 2, 3, 4};// 3. 从QVariantList转换
QVariantList varList{"a", "b", "c"};
QJsonArray arr3 = QJsonArray::fromVariantList(varList);// 4. 嵌套构造(数组包含对象)
QJsonArray arr4{QJsonObject{{"id", 1}, {"name", "item1"}},QJsonObject{{"id", 2}, {"name", "item2"}}
};
2. 元素的添加、插入与删除

QJsonArray提供索引化操作接口,支持动态调整元素:

QJsonArray arr;// 尾部添加元素
arr.append(10);                  // 添加数值
arr.append("text");              // 添加字符串
arr.append(QJsonObject{{"k", "v"}}); // 添加对象// 指定位置插入元素
arr.insert(1, true);             // 在索引1处插入布尔值// 删除元素
arr.removeAt(0);                 // 删除索引0的元素
arr.pop_back();                  // 删除最后一个元素(Qt 5.10+)
arr.pop_front();                 // 删除第一个元素(Qt 5.10+)
3. 元素访问与修改

通过索引访问元素,支持读写操作:

// 获取元素(at()返回const引用,operator[]返回可修改引用)
QJsonValue first = arr.at(0);    // 只读访问,越界返回Null
QJsonValue second = arr[1];      // 可修改访问// 修改元素
arr[0] = 20;                     // 直接赋值修改// 获取数组大小
int size = arr.size();
bool isEmpty = arr.isEmpty();// 安全访问(避免越界)
if (index >= 0 && index < arr.size()) {QJsonValue val = arr[index];
}
4. 遍历与迭代

QJsonArray支持索引遍历和迭代器遍历:

// 1. 索引遍历
for (int i = 0; i < arr.size(); ++i) {QJsonValue val = arr[i];// 处理元素
}// 2. STL风格迭代(只读)
for (auto it = arr.constBegin(); it != arr.constEnd(); ++it) {qDebug() << *it;
}// 3. STL风格迭代(可修改)
for (auto it = arr.begin(); it != arr.end(); ++it) {if (it->isDouble()) {*it = it->toDouble() * 2; // 数值翻倍}
}
5. 与QVariantList的转换

类似QJsonObject,QJsonArray可与QVariantList双向转换:

// QJsonArray → QVariantList
QVariantList varList = arr.toVariantList();// QVariantList → QJsonArray
QJsonArray arrFromList = QJsonArray::fromVariantList(varList);

五、QJsonDocument:JSON文档的解析与序列化

QJsonDocument是JSON数据的顶层容器,负责JSON文本与Qt JSON对象/数组的相互转换,是数据输入输出的核心。

1. 构造与初始化

QJsonDocument可从QJsonObject或QJsonArray构造,代表一个完整的JSON文档:

// 从对象构造
QJsonObject obj{{"key", "value"}};
QJsonDocument doc1(obj);// 从数组构造
QJsonArray arr{1, 2, 3};
QJsonDocument doc2(arr);// 空文档(isNull()返回true)
QJsonDocument emptyDoc;
2. JSON解析(从文本到对象/数组)

通过fromJson()方法解析JSON文本(UTF-8编码),支持字符串或二进制数据:

// 待解析的JSON字符串(必须是UTF-8编码)
QByteArray jsonData = R"({"name":"Qt","version":6.5})";// 解析并处理错误
QJsonParseError error;
QJsonDocument doc = QJsonDocument::fromJson(jsonData, &error);if (error.error != QJsonParseError::NoError) {qDebug() << "解析错误:" << error.errorString() << "位置:" << error.offset;return;
}// 判断文档类型(对象或数组)
if (doc.isObject()) {QJsonObject obj = doc.object(); // 转换为对象
} else if (doc.isArray()) {QJsonArray arr = doc.array();   // 转换为数组
}

解析注意事项

  • 输入必须是UTF-8编码的JSON文本,其他编码(如GBK)需先转换为UTF-8;
  • JSON文本必须是完整的对象或数组(不能是单独的字符串/数字);
  • 解析错误时,error对象会包含错误类型(如InvalidEscapeSequenceMismatchedBrace)和错误位置。
3. JSON序列化(从对象/数组到文本)

通过toJson()方法将文档转换为JSON文本,支持格式控制:

QJsonDocument doc = ...;// 1. 紧凑格式(无缩进,最小化输出)
QByteArray compactJson = doc.toJson(QJsonDocument::Compact);// 2. 缩进格式(便于阅读,默认4空格缩进)
QByteArray indentedJson = doc.toJson(QJsonDocument::Indented);// 输出示例:
// Compact: {"name":"Qt","version":6.5}
// Indented: {
//     "name": "Qt",
//     "version": 6.5
// }

序列化特性

  • 输出始终为UTF-8编码;
  • 特殊字符(如引号、控制字符)会自动转义;
  • 数值序列化会保留精度(如整数123不会显示为123.0)。
4. 与文件的交互

结合QFile可实现JSON文件的读写:

// 写入JSON文件
QJsonObject obj{{"data", "example"}};
QJsonDocument doc(obj);
QFile file("output.json");
if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {file.write(doc.toJson(QJsonDocument::Indented));file.close();
}// 读取JSON文件
if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {QByteArray data = file.readAll();file.close();QJsonDocument readDoc = QJsonDocument::fromJson(data);// 处理读取的文档
}

六、高级特性与最佳实践

1. 嵌套结构处理

Qt JSON类支持任意深度的嵌套(对象包含数组,数组包含对象等),需注意逐层访问以避免错误:

// 构建嵌套结构:对象包含数组,数组包含对象
QJsonObject root;
QJsonArray items;
items.append(QJsonObject{{"id", 1}, {"name", "item1"}});
items.append(QJsonObject{{"id", 2}, {"name", "item2"}});
root["items"] = items;
root["page"] = 1;// 解析嵌套结构
QJsonDocument doc(root);
QJsonObject parsedRoot = doc.object();
if (parsedRoot.contains("items") && parsedRoot["items"].isArray()) {QJsonArray parsedItems = parsedRoot["items"].toArray();for (const QJsonValue &itemVal : parsedItems) {if (itemVal.isObject()) {QJsonObject itemObj = itemVal.toObject();qDebug() << "ID:" << itemObj["id"].toInt();}}
}
2. 性能与内存考量
  • 隐式数据共享:QJsonObject、QJsonArray等类采用隐式数据共享(copy-on-write),复制操作开销低,修改时才真正复制数据;
  • 大型JSON处理:解析几MB以上的JSON时,建议使用QJsonDocument::fromJson()QByteArray重载,避免中间字符串转换;
  • 内存释放:复杂嵌套结构会占用较多内存,不再使用时需确保所有引用都被释放(尤其是迭代器和临时对象)。
3. 类型安全与错误处理
  • 始终先判断QJsonValue的类型,再调用对应的取值方法(如if (val.isString()) val.toString());
  • 解析JSON时必须检查QJsonParseError,避免因格式错误导致程序崩溃;
  • 处理网络获取的JSON数据时,需先验证数据结构(如必要的键是否存在),再进行解析。
4. 与网络模块的协同

在网络请求中(如QNetworkAccessManager),常需解析响应数据为JSON:

// 假设reply是QNetworkReply指针
connect(reply, &QNetworkReply::finished, [reply]() {if (reply->error() == QNetworkReply::NoError) {QByteArray data = reply->readAll();QJsonParseError error;QJsonDocument doc = QJsonDocument::fromJson(data, &error);if (error.error == QJsonParseError::NoError) {// 处理JSON文档}}reply->deleteLater();
});

七、常见问题与解决方案

  1. 中文乱码:JSON文本必须是UTF-8编码,若源数据为其他编码(如GBK),需用QTextCodec转换为UTF-8后再解析;
  2. 大整数精度丢失:JSON数值以double存储,超过53位的整数需以字符串形式存储,解析时手动转换为qint64
  3. 嵌套过深导致栈溢出:递归遍历深度超过1000层的JSON结构可能导致栈溢出,建议改用迭代方式遍历;
  4. 键名重复:QJsonObject允许通过insert()覆盖重复键,若需保留所有键(非标准JSON行为),需手动处理为数组。

Qt的QJsonObject、QJsonArray、QJsonDocument和QJsonValue共同构成了完整的JSON处理体系,其设计兼顾了易用性与灵活性。QJsonValue作为基础值容器,支撑了JSON类型系统;QJsonObject和QJsonArray分别管理键值对和有序列表,实现了复合结构;QJsonDocument则承担了数据解析与序列化的重任。


文章转载自:

http://JmLKA9br.dkbgg.cn
http://KzHW8xwD.dkbgg.cn
http://6exzLaAF.dkbgg.cn
http://4m9ZkoxW.dkbgg.cn
http://CzZWDMit.dkbgg.cn
http://FdeDoFeS.dkbgg.cn
http://cZHs1CCr.dkbgg.cn
http://nnZ7i7j6.dkbgg.cn
http://WdCuevPD.dkbgg.cn
http://OwaBGsXf.dkbgg.cn
http://KSMwPcs1.dkbgg.cn
http://EQXaFCMn.dkbgg.cn
http://TaOLsQIw.dkbgg.cn
http://s8pGDCdI.dkbgg.cn
http://phbg5Rqx.dkbgg.cn
http://8QlZyk5Q.dkbgg.cn
http://FtEoLBua.dkbgg.cn
http://HLvQwDEF.dkbgg.cn
http://UsbpYxS6.dkbgg.cn
http://XbBZo82B.dkbgg.cn
http://pQI7fDPT.dkbgg.cn
http://jjaufxDV.dkbgg.cn
http://7YRUTneU.dkbgg.cn
http://f1b3edO1.dkbgg.cn
http://VKog0J05.dkbgg.cn
http://Te430kFd.dkbgg.cn
http://K5dDmkqW.dkbgg.cn
http://oivi5otv.dkbgg.cn
http://zLnVuE6t.dkbgg.cn
http://0I27nsaf.dkbgg.cn
http://www.dtcms.com/a/368943.html

相关文章:

  • 基于YOLOv8的车辆轨迹识别与目标检测研究分析软件源代码+详细文档
  • 行业了解06:物流运输业
  • 碰一碰系统+手机端全线一站式开发源码技术saas搭建步骤:
  • uniapp 封装uni.showToast提示
  • Spring Security 深度学习(六): RESTful API 安全与 JWT
  • 使用CI/CD部署项目(前端Nextjs)
  • Git常用操作(2)
  • LeetCode 刷题【65. 有效数字】
  • Android,jetpack Compose模仿QQ侧边栏
  • 让语言模型自我进化:探索 Self-Refine 的迭代反馈机制
  • Kubernetes(k8s) po 配置持久化挂载(nfs)
  • 支持二次开发的代练App源码:订单管理、代练监控、安全护航功能齐全,一站式解决代练护航平台源码(PHP+ Uni-app)
  • proble1111
  • Ubuntu 24.04.2安装k8s 1.33.4 配置cilium
  • nextcyber——暴力破解
  • Process Explorer 学习笔记(第三章3.2.3):工具栏与参考功能
  • C++两个字符串的结合
  • c51串口通信原理及实操
  • Java垃圾回收算法详解:从原理到实践的完整指南
  • MongoDB 6.0 新特性解读:时间序列集合与加密查询
  • IAR借助在瑞萨RH850/U2A MCU MCAL支持,加速汽车软件开发
  • 状压 dp --- 棋盘覆盖问题
  • 机器学习周报十二
  • 力扣:2322. 从树中删除边的最小分数
  • 人工智能常见分类
  • C++ 音视频开发常见面试题及答案汇总
  • C/C++ Linux系统编程:线程控制详解,从线程创建到线程终止
  • swoole 中 Coroutine\WaitGroup 和channel区别和使用场景
  • HDFS架构核心
  • Python的语音配音软件,使用edge-tts进行文本转语音,支持多种声音选择和语速调节