Qt 高效读写JSON文件,玩转QJsonDocument与QJsonObject

发布于:2025-03-25 ⋅ 阅读:(34) ⋅ 点赞:(0)

一、前言

JSON作为轻量级的数据交换格式,已成为开发者必备技能。Qt框架为JSON处理提供了完整的解决方案,通过QJsonDocumentQJsonObjectQJsonArray三大核心类,轻松实现数据的序列化与反序列化。

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);

七、性能优化建议

  1. 大文件处理

    • 使用流式解析(QJsonDocument不适合GB级文件)

    • 考虑第三方库(如RapidJSON)处理超大JSON

  2. 内存管理

    // 及时释放不再使用的JSON对象
    {
        QJsonObject tempObj;
        // 操作临时对象
    } // 自动释放内存
  3. 缓存机制

    • 对频繁读取的配置进行内存缓存

    • 使用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);
    }
};

九、实践总结

  1. 文件操作规范

    • 使用QSaveFile实现原子写入

    • 设置文件权限:QFileDevice::ReadOwner | QFileDevice::WriteOwner

  2. 版本兼容性

    {
        "metadata": {
            "schemaVersion": "1.1",
            "createdAt": "2023-08-20"
        }
    }
  3. 安全建议

    • 校验JSON数据完整性

    • 限制最大文件尺寸

    • 敏感数据加密存储