一、前言
JSON作为轻量级的数据交换格式,已成为开发者必备技能。Qt框架为JSON处理提供了完整的解决方案,通过QJsonDocument
、QJsonObject
和QJsonArray
三大核心类,轻松实现数据的序列化与反序列化。
JSON vs INI
特性 | JSON | INI |
---|---|---|
数据结构 | 支持嵌套对象/数组 | 扁平键值对 |
数据类型 | 丰富(含null) | 仅字符串 |
适用场景 | 复杂配置/网络传输 | 简单配置 |
二、环境准备
2.1 项目配置
在.pro
文件中添加JSON模块:
QT += core
2.2 包含头文件
#include <QJsonDocument> #include <QJsonObject> #include <QJsonArray> #include <QFile>
三、核心API详解
3.1 QJsonDocument类
方法 | 说明 | 示例 |
---|---|---|
fromJson(jsonData, error) | 解析JSON数据 | QJsonParseError err; doc = QJsonDocument::fromJson(data, &err) |
toJson(format) | 序列化为字符串 | QByteArray json = doc.toJson(QJsonDocument::Indented) |
object() | 获取根对象 | QJsonObject root = doc.object() |
array() | 获取根数组 | QJsonArray arr = doc.array() |
isObject() | 是否对象类型 | if(doc.isObject()) |
isArray() | 是否数组类型 | if(doc.isArray()) |
setObject(obj) | 设置根对象 | doc.setObject(newObj) |
setArray(arr) | 设置根数组 | doc.setArray(newArr) |
3.2 QJsonObject类
方法 | 说明 | 示例 |
---|---|---|
insert(key, value) | 插入键值对 | obj.insert("name", "Alice") |
remove(key) | 删除指定键 | obj.remove("obsoleteKey") |
contains(key) | 检查键是否存在 | if(obj.contains("timestamp")) |
value(key) | 安全获取值 | QJsonValue val = obj.value("age") |
operator[](key) | 直接访问值 | obj["score"] = 95.5 |
keys() | 获取所有键列表 | QStringList keys = obj.keys() |
size() | 获取键值对数量 | qDebug() << "对象大小:" << obj.size() |
isEmpty() | 判断是否为空 | if(obj.isEmpty()) return; |
3.3 QJsonArray 类
方法 | 说明 | 示例 |
---|---|---|
append(value) | 追加元素 | arr.append(42) |
insert(index, value) | 插入元素 | arr.insert(0, "First") |
removeAt(index) | 删除指定位置元素 | arr.removeAt(3) |
replace(index, value) | 替换元素 | arr.replace(2, true) |
at(index) | 获取指定位置值 | QJsonValue val = arr.at(0) |
size() | 获取元素数量 | for(int i=0; i<arr.size(); ++i) |
isEmpty() | 判断是否为空 | if(arr.isEmpty()) return; |
3.4 QJsonValue类型处理
方法 | 说明 |
---|---|
isBool() | 布尔类型 |
isDouble() | 数值类型 |
isString() | 字符串类型 |
isArray() | JSON数组 |
isObject() | JSON对象 |
isNull() | 空值 |
isUndefined() | 未定义值 |
安全转换方法:
QJsonValue val = /* ... */;// 带默认值的转换
int num = val.toInt(0); // 转换失败返回0
QString str = val.toString("default");// 带错误检测的转换
bool ok;
double d = val.toDouble(&ok);
if(!ok) qWarning() << "转换double失败";// 对象/数组转换
if(val.isObject()) {QJsonObject obj = val.toObject();
}
else if(val.isArray()) {QJsonArray arr = val.toArray();
}// 特殊类型处理
QJsonValue nullVal = QJsonValue::Null;
QJsonValue undefinedVal; // 默认构造为Undefined
四、读写JSON
4.1 写入JSON文件,创建复杂JSON结构
void writeJsonFile()
{// 创建根对象QJsonObject rootObj;// 基础数据rootObj["appName"] = "QtConfigManager";rootObj["version"] = "1.2.0";rootObj["debugMode"] = false;// 嵌套对象QJsonObject dbConfig;dbConfig["host"] = "127.0.0.1";dbConfig["port"] = 3306;dbConfig["credentials"] = QJsonArray{"root", "123456"};rootObj["database"] = dbConfig;// 创建数组QJsonArray recentFiles;recentFiles.append("project1.pro");recentFiles.append("mainwindow.cpp");rootObj["recentFiles"] = recentFiles;// 生成JSON文档QJsonDocument doc(rootObj);// 写入文件QFile file("config.json");if(file.open(QIODevice::WriteOnly)){file.write(doc.toJson(QJsonDocument::Indented));file.close();qDebug() << "JSON文件写入成功!";} else {qWarning() << "文件打开失败:" << file.errorString();}
}
4.2 读取JSON文件
void readJsonFile()
{QFile file("config.json");if(!file.open(QIODevice::ReadOnly)) {qCritical() << "文件打开失败:" << file.errorString();return;}// 解析JSONQJsonDocument doc = QJsonDocument::fromJson(file.readAll());if(doc.isNull()){qWarning() << "JSON解析失败!";return;}// 获取根对象QJsonObject root = doc.object();// 读取基础配置QString appName = root["appName"].toString();bool debugMode = root["debugMode"].toBool();// 解析嵌套对象QJsonObject dbConfig = root["database"].toObject();QString host = dbConfig["host"].toString();QJsonArray credentials = dbConfig["credentials"].toArray();// 遍历数组QJsonArray files = root["recentFiles"].toArray();qDebug() << "最近文件列表:";for(const QJsonValue &val : files){qDebug() << "->" << val.toString();}// 安全取值示例int port = dbConfig.value("port").toInt(3306); // 默认值
}
五、实战技巧:处理复杂场景
5.1 动态键名处理
QJsonObject config; QString dynamicKey = "custom_" + QString::number(QDateTime::currentSecsSinceEpoch()); config[dynamicKey] = "特殊配置项";
5.2 日期时间处理
// 写入 QJsonObject obj; obj["timestamp"] = QDateTime::currentDateTime().toString(Qt::ISODate);// 读取 QDateTime dt = QDateTime::fromString(obj["timestamp"].toString(), Qt::ISODate);
5.3 二进制数据编码
// Base64编码存储 QByteArray imageData = /*...*/; obj["avatar"] = QString(imageData.toBase64());// 解码读取 QByteArray restoredData = QByteArray::fromBase64(obj["avatar"].toString().toUtf8());
六、错误处理与调试
6.1 错误检测
QJsonParseError parseError; QJsonDocument doc = QJsonDocument::fromJson(rawData, &parseError);if(parseError.error != QJsonParseError::NoError){qDebug() << "JSON解析错误:" << parseError.errorString()<< "at offset" << parseError.offset; }
6.2 调试输出
// 格式化输出JSON qDebug().noquote() << doc.toJson(QJsonDocument::Indented);
七、性能优化建议
-
大文件处理:
-
使用流式解析(
QJsonDocument
不适合GB级文件) -
考虑第三方库(如RapidJSON)处理超大JSON
-
-
内存管理:
// 及时释放不再使用的JSON对象 {QJsonObject tempObj;// 操作临时对象 } // 自动释放内存
-
缓存机制:
-
对频繁读取的配置进行内存缓存
-
使用
QCache
实现LRU缓存
-
八、扩展应用:与QVariant互转
8.1 对象转换
// JSON转QVariantMap QVariantMap vmap = doc.object().toVariantMap();// QVariantMap转JSON QJsonObject::fromVariantMap(vmap);
8.2 序列化对象
class UserSettings { public:void saveToJson(QJsonObject &json) const {json["theme"] = m_theme;json["fontSize"] = m_fontSize;}void loadFromJson(const QJsonObject &json) {m_theme = json["theme"].toString();m_fontSize = json.value("fontSize").toInt(12);} };
九、实践总结
-
文件操作规范:
-
使用
QSaveFile
实现原子写入 -
设置文件权限:
QFileDevice::ReadOwner | QFileDevice::WriteOwner
-
-
版本兼容性:
{"metadata": {"schemaVersion": "1.1","createdAt": "2023-08-20"} }
-
安全建议:
-
校验JSON数据完整性
-
限制最大文件尺寸
-
敏感数据加密存储
-