一、前言
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數據完整性
-
限制最大文件尺寸
-
敏感數據加密存儲
-