一、前言
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;
}
// 解析JSON
QJsonDocument 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数据完整性
-
限制最大文件尺寸
-
敏感数据加密存储
-