Qt QJsonDocument 10分钟讲清楚

一、QJsonDocument 概述

QJsonDocument是 Qt 中处理 JSON 数据的核心容器类 ,属于 QtCore模块(需包含头文件 <QJsonDocument>,并在 .pro中添加 QT += core)。它的核心作用是:

  • 解析 ​ JSON 字符串/字节流为结构化的 Qt 对象(QJsonObject/QJsonArray);

  • 生成 ​ JSON 字符串/字节流(从 QJsonObject/QJsonArray转换);

  • 封装 ​ JSON 文档的根元素(JSON 根必须是对象数组,不能是单个值)。

Qt 的 JSON 模块是**轻量级、隐式共享(Implicitly Shared)**的,适合嵌入式场景,资源占用低且性能足够。

二、核心功能与用法

1. 解析 JSON(从字符串/字节流到 Qt 对象)

使用静态方法 QJsonDocument::fromJson()解析 JSON 数据,需传入UTF-8 编码的 QByteArray (若源是 QString,需用 toUtf8()转换)。

关键细节:
  • 错误处理 :通过 QJsonParseError结构体获取解析错误(如语法错误、非法字符);

  • 根元素判断 :解析后需用 isObject()/isArray()判断根类型是对象还是数组。

示例:解析 JSON 字符串

cpp 复制代码
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QDebug>

void parseJsonExample() {
    // 1. 待解析的 JSON 字符串(UTF-8)
    QString jsonStr = R"({
        "device": "Portable Monitor",
        "model": "PM-2024",
        "stream": {
            "url": "rtsp://192.168.1.100/live",
            "codec": "H265",
            "resolution": "1920x1080",
            "fps": 30
        },
        "status": ["online", "recording"]
    })";

    // 2. 转换为 UTF-8 字节流
    QByteArray jsonData = jsonStr.toUtf8();

    // 3. 解析并捕获错误
    QJsonParseError parseError;
    QJsonDocument doc = QJsonDocument::fromJson(jsonData, &parseError);

    if (parseError.error != QJsonParseError::NoError) {
        qDebug() << "JSON 解析失败:" << parseError.errorString() 
                 << "(位置:" << parseError.offset << ")";
        return;
    }

    // 4. 访问根元素(此处是对象)
    if (doc.isObject()) {
        QJsonObject rootObj = doc.object();

        // 读取简单键值
        QString device = rootObj["device"].toString(); // "Portable Monitor"
        QString model = rootObj["model"].toString();   // "PM-2024"

        // 读取嵌套对象(stream)
        QJsonObject streamObj = rootObj["stream"].toObject();
        QString rtspUrl = streamObj["url"].toString();       // "rtsp://..."
        QString codec = streamObj["codec"].toString();       // "H265"
        int fps = streamObj["fps"].toInt();                   // 30

        // 读取数组(status)
        QJsonArray statusArr = rootObj["status"].toArray();
        for (const QJsonValue &val : statusArr) {
            qDebug() << "状态:" << val.toString(); // "online", "recording"
        }
    }
}

2. 生成 JSON(从 Qt 对象到字符串/字节流)

使用 QJsonDocument::toJson()QJsonObject/QJsonArray转换为 JSON 字符串,支持两种格式:

  • QJsonDocument::Compact紧凑模式(无缩进,适合网络传输);

  • QJsonDocument::Indented缩进模式(带换行和空格,适合日志/调试)。

示例:生成 JSON 配置

cpp 复制代码
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QDebug>

void generateJsonExample() {
    // 1. 构建嵌套的 JSON 对象(模拟流媒体配置)
    QJsonObject streamObj;
    streamObj["url"] = "rtsp://192.168.1.101/preview";
    streamObj["codec"] = "H264";
    streamObj["resolution"] = "1280x720";
    streamObj["fps"] = 25;
    streamObj["protocol"] = "TCP"; // 流媒体常用 TCP/UDP

    // 2. 构建根对象
    QJsonObject rootObj;
    rootObj["device"] = "Portable Monitor";
    rootObj["model"] = "PM-2024";
    rootObj["stream"] = streamObj; // 嵌套对象
    rootObj["features"] = QJsonArray::fromStringList({"HDMI", "USB-C", "WiFi"}); // 数组

    // 3. 封装为 QJsonDocument(根元素是对象)
    QJsonDocument doc(rootObj);

    // 4. 转换为 JSON 字符串(缩进模式,方便阅读)
    QByteArray jsonData = doc.toJson(QJsonDocument::Indented);
    QString jsonStr = QString::fromUtf8(jsonData);

    qDebug() << "生成的 JSON:\n" << jsonStr;
    /* 输出:
    {
        "device": "Portable Monitor",
        "features": ["HDMI", "USB-C", "WiFi"],
        "model": "PM-2024",
        "stream": {
            "codec": "H264",
            "fps": 25,
            "protocol": "TCP",
            "resolution": "1280x720",
            "url": "rtsp://192.168.1.101/preview"
        }
    }
    */
}

3. 核心方法与属性

方法/属性 说明
QJsonDocument() 默认构造(空文档,isNull()/isEmpty()均为 true
QJsonDocument(const QJsonObject&) 用 JSON 对象初始化(根为对象)
QJsonDocument(const QJsonArray&) 用 JSON 数组初始化(根为数组)
static QJsonDocument fromJson(const QByteArray&, QJsonParseError*) 解析 JSON 字节流,返回文档+错误信息
QByteArray toJson(Format format = Compact) 转换为 JSON 字节流(Compact/Indented
bool isObject() const 根元素是否为 JSON 对象
bool isArray() const 根元素是否为 JSON 数组
QJsonObject object() const 获取根对象(若根是数组,返回空对象)
QJsonArray array() const 获取根数组(若根是对象,返回空数组)
bool isEmpty() const 文档是否为空(默认构造或未初始化)
bool isNull() const 文档是否无效(同 isEmpty(),部分版本差异可忽略)
void swap(QJsonDocument&) 交换两个文档的内容(高效)

三、与其他 QJson 类的协作

QJsonDocument容器,需配合以下类完成完整的 JSON 处理:

类名 作用
QJsonValue JSON 基本值的封装(null/bool/int/double/string/object/array
QJsonObject JSON 对象(键值对集合,类似 std::map<QString, QJsonValue>
QJsonArray JSON 数组(有序值集合,类似 QList<QJsonValue>
QJsonParseError 解析错误的详细信息(error枚举+offset错误位置)

关系链

QJsonDocument→ 包含 QJsonObject/QJsonArray→ 包含 QJsonValue→ 对应 JSON 基本类型。

四、实际场景应用

用 ZynqMP + Qt 开发,流媒体是核心方向。QJsonDocument可用于以下场景:

1. 流媒体配置管理

用 JSON 存储设备的流媒体参数(如 RTSP 地址、编码格式、分辨率),通过 QJsonDocument解析后配置播放器。

示例配置 JSON

复制代码
{
    "stream": {
        "input": "rtsp://admin:123@192.168.1.100/stream1",
        "decoder": "H265",
        "resolution": "1920x1080",
        "fps": 30,
        "buffer_size": 1024
    },
    "display": {
        "brightness": 70,
        "contrast": 50,
        "fullscreen": false
    }
}

解析后 :提取 stream.input给 GStreamer/FFmpeg 播放器,display.brightness调整屏幕亮度。

2. 设备状态上报

将监视器的实时状态(如播放状态、码率、温度、剩余电量)封装为 JSON,通过 HTTP/MQTT 上报到服务器。

示例状态 JSON

复制代码
{
    "device_id": "PM-2024-001",
    "timestamp": 1718236800,
    "status": {
        "play_state": "playing",
        "bitrate": 2048,
        "fps": 29.97,
        "temperature": 45,
        "battery": 80
    }
}

生成后 :用 QNetworkAccessManager发送 POST 请求。

3. 固件/配置更新

通过 JSON 描述更新包的信息(版本号、下载地址、校验和),解析后触发 OTA 升级。

五、注意事项与常见问题

1. 编码问题

JSON 标准要求UTF-8 编码QJsonDocument仅支持 UTF-8。若源数据是 GBK 等其他编码,需先转换为 UTF-8(用 QString::fromLocal8Bit()QTextCodec)。

2. 根元素限制

JSON 根必须是对象数组,不能直接是字符串/数字。若要存储单个值,需用对象包装:

复制代码
// 错误:根是字符串
// QJsonDocument doc("hello"); 

// 正确:用对象包装
QJsonObject obj;
obj["message"] = "hello";
QJsonDocument doc(obj);

3. 错误处理

解析前务必检查 QJsonParseError

  • 常见错误:QJsonParseError::IllegalValue(非法值)、QJsonParseError::MissingObject(缺少对象)、QJsonParseError::SyntaxError(语法错误)。

4. 性能优化

  • 隐式共享QJsonDocument拷贝时是浅拷贝,修改时才深拷贝,避免不必要的内存开销;

  • 大文档处理 :若 JSON 文档过大(如超过 10MB),建议用流式解析(Qt 未提供原生流式 API,可考虑第三方库如 simdjson),但嵌入式场景下很少遇到。

5. 键不存在的处理

访问 QJsonObject的不存在的键时,返回无效的 QJsonValueisUndefined()true)。需用以下方式安全取值:

复制代码
QJsonObject obj = ...;
// 方法1:先判断键存在
if (obj.contains("stream_url")) {
    QString url = obj["stream_url"].toString();
}
// 方法2:用 value() 取默认值
QString url = obj.value("stream_url").toString("rtsp://default.url");

六、扩展:QVariant 与 JSON 的转换

QJsonDocument提供 fromVariant()/toVariant()方法,可将 QVariantMap(对应 JSON 对象)、QVariantList(对应 JSON 数组)与 JSON 互转,简化 Qt 数据结构与 JSON 的交互:

复制代码
// QVariantMap → JSON
QVariantMap config;
config["device"] = "PM-2024";
config["stream_url"] = "rtsp://...";
QJsonDocument doc = QJsonDocument::fromVariant(config);

// JSON → QVariantMap
QVariantMap config2 = doc.toVariant().toMap();

总结

QJsonDocument是 Qt 处理 JSON 的核心入口 ,结合 QJsonObject/QJsonArray可轻松实现 JSON 的解析与生成。

相关推荐
寻寻觅觅☆5 小时前
东华OJ-基础题-106-大整数相加(C++)
开发语言·c++·算法
l1t5 小时前
在wsl的python 3.14.3容器中使用databend包
开发语言·数据库·python·databend
赶路人儿6 小时前
Jsoniter(java版本)使用介绍
java·开发语言
ceclar1236 小时前
C++使用format
开发语言·c++·算法
码说AI7 小时前
python快速绘制走势图对比曲线
开发语言·python
Gofarlic_OMS7 小时前
科学计算领域MATLAB许可证管理工具对比推荐
运维·开发语言·算法·matlab·自动化
星空下的月光影子7 小时前
易语言开发从入门到精通:补充篇·网络爬虫与自动化采集分析系统深度实战·HTTP/HTTPS请求·HTML/JSON解析·反爬策略·电商价格监控·新闻资讯采集
开发语言
老约家的可汗7 小时前
初识C++
开发语言·c++
wait_luky7 小时前
python作业3
开发语言·python
消失的旧时光-19437 小时前
第十九课:为什么要引入消息队列?——异步系统设计思想
java·开发语言