• Qt中的JSON支持


    JSON介绍

    Qt支持处理JSON数据。JSON是一种对源自Javascript的对象数据进行编码的格式,但现在被广泛用作互联网上的数据交换格式。

    Qt中的JSON支持提供了一个易于使用的C++API来解析、修改和保存JSON数据。它还支持以二进制格式保存数据,这种格式可以直接“mmap”,并且访问速度非常快。

    JSON数据格式的更多详细信息可以在JSON中找到。
    https://www.json.org/json-en.html和RFC-4627
    https://www.rfc-editor.org/rfc/rfc4627

    JSON概述

    JSON是一种存储结构化数据的格式。它有6种基本数据类型:

    bool
    double
    string
    array
    object
    null
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    值可以具有上述任何类型。bool由JSON中的字符串true或false表示。JSON没有明确指定数字的有效范围,但Qt中的支持仅限于双精度的有效范围和精度。字符串可以是任何有效的unicode字符串。数组是值的列表,对象是键/值对的集合。对象中的所有键都是字符串,并且对象不能包含任何重复的键。

    JSON的文本表示包含方括号([…])中的数组和花括号({…})中的对象。数组和对象中的条目用逗号分隔。对象中键和值之间的分隔符是冒号(:)。

    一个简单的JSON文档,对一个人、他的/她的年龄、地址和电话号码进行编码,其内容如下:

     {
         "FirstName": "Zhang",
         "LastName": "San",
         "Age": 24,
         "Address": 
         {
             "Street": "Downing Street 10",
             "City": "ShangHai",
             "Country": "Great Britain"
         },
         "Phone numbers": 
         [
             "+22 1234567",
             "+22 2345678"
         ]
     }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    上面的示例由一个具有5个键/值对的对象组成。其中两个值是字符串,一个是数字,另一个是对象,最后一个是数组。

    有效的JSON文档是数组或对象,因此文档总是以方括号或花括号开头。

    所有JSON类都是基于值的隐式共享类。

    Qt中的JSON支持包括以下类:

    QJsonArray封装JSON数组
    
    QJsonDocument读取和写入JSON文档方法
    
    QJsonObject封装JSON对象
    
    QJsonParseError用于报告JSON解析过程中的错误
    
    QJsonValue将值封装为JSON
    
    QJsonObject::const_iteratorQJsonObject::const_isterator类为QJsonObjects提供了一个STL风格的常量迭代器
    
    QJsonObject::iteratorQJsonObject::iterator类为QJsonObject提供了一个STL风格的非常量迭代器
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    QJsonValue

    QJsonValue类将值封装在JSON中。

    JSON中的值可以是6种基本类型之一:

    支持的类型

    JSON是一种存储结构化数据的格式。它有6种基本数据类型:

    QJsonValue::Type	描述
    QJsonValue::Null	null值
    QJsonValue::Bool	存储的是bool值,可以通过toBool转换为bool类型
    QJsonValue::Double	存储的是double值,可以通过toDouble转换为double类型
    QJsonValue::String	存储的是字符串类型,可以通过toString转换为QString类型
    QJsonValue::Array	存储的是数组,可以通过toArray转换为QJsonArray类型
    QJsonValue::Object	存储的json对象,可以通过toObject转换为QJsonObject类型
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    值可以表示上述任何数据类型。此外,QJsonValue有一个特殊的标志来表示未定义的值。这可以使用isUndefined()查询。

    可以使用type()或isBool()、isString()等访问器查询值的类型。同样,可以使用toBool(()、toString()等等将值转换为存储在其中的类型。

    值是内部严格类型化的,与QVariant相反。它不会尝试进行任何隐式类型转换。这意味着转换为未存储在值中的类型将返回默认构造的返回值。

    可以通过type方法获取当前存储的类型,例如:

    QJsonValue value(false);
    qDebug() << value.type();
    
    • 1
    • 2

    当然还有一些类型判断,如下:

    QJsonValue value(false);
    qDebug() << value.isBool();
    qDebug() << value.isObject();
    
    • 1
    • 2
    • 3

    构建

    可以通过支持的类型直接构建,例如:

    QJsonValue value(false);
    QJsonValue value(1);
    QJsonValue value("A");
    QJsonValue value(QJsonArray({ 1, 2 }));
    QJsonValue value(QJsonObject({ { "A", "zhangsan" }, { "B", 10 } }));
    
    • 1
    • 2
    • 3
    • 4
    • 5

    QJsonObject

    1、QJsonObject类封装了一个JSON对象。

    2、JSON对象是键值对的列表,其中键是唯一的字符串,值由QJsonValue表示。

    3、QJsonObject可以转换为QVariantMap,也可以从QVariantMap转换。您可以使用size()、insert()和remove()条目查询(键、值)对的数量,并使用标准C++迭代器模式对其内容进行迭代。

    4、QJsonObject是一个隐式共享的类,只要没有修改,它就与创建它的文档共享数据。

    5、您可以通过QJsonDocument将对象转换为基于文本的JSON。

    构建

    1 . 可以通过初始化列表构造QJsonObject对象,例如:

    QJsonObject object({ { "year", "2022" }, { "month", 12 }, {"day", 6} });
    qDebug().noquote() << "3333333333333333333333" << QJsonDocument(object).toJson();
    
    • 1
    • 2

    输出:

    3333333333333333333333 {
        "day": 6,
        "month": 12,
        "year": "2022"
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2 . QVarientMap和QVarientHash里放的就是多个键值对,也正好符合Json对象的形式,所以,QJsonObject提供了下面两个静态方法:

    static QJsonObject fromVariantMap(const QVariantMap &map);
    static QJsonObject fromVariantHash(const QVariantHash &map);
    
    • 1
    • 2

    当然也可以将QJsonObject转换为QVarientMap或者QVarientHash

    QVariantHash toVariantHash() const;
    QVariantMap toVariantMap() const;
    
    • 1
    • 2

    3 . 动态构建QJsonObject,通过使用insert方法添加键值对,例如:

    object.insert("A", "zhangsan");
    object.insert("B", 15);
    qDebug().noquote() << QJsonDocument(object).toJson();
    
    • 1
    • 2
    • 3

    输出:

    {
    “B”: 15,
    “A”: “zhangsan”
    }

    注意

    QJsonObject中插入键值对后是会按键排序的,不会保持insert的顺序,类似QMap。
    QJsonObject中存储容量是有上限的,源码中,插入新值会执行reserveSpace,里面有个容量上限

    int Base::reserveSpace(uint dataSize, int posInTable, uint numItems, bool replace)
    {
        Q_ASSERT(posInTable >= 0 && posInTable <= (int)length);
        if (size + dataSize >= Value::MaxSize) {
            qWarning("QJson: Document too large to store in data structure %d %d %d", (uint)size, dataSize, Value::MaxSize);
            return 0;
        }
        ...
    }
    
    enum {
        MaxSize = (1<<27) - 1
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    取值、 查找、遍历、删除

    QJsonObject object({ { "A", "zhangsan" }, { "B", 15 } });
    // 取值
    qDebug() << object.value("A");
    qDebug() << object["A"];
    
    // 查找
    qDebug() << object.contains("A");
    auto iter = object.find("A");
    
    // 遍历
    for (auto iter = object.begin(); iter != object.end(); iter++)
        qDebug() << iter.key() << iter.value();
    
    // 删除
    object.remove("A");
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    JSON数组

    1、QJsonArray类封装了一个JSON数组。
    2、JSON数组是一个值列表。可以通过从数组中插入和删除QJsonValue来操作列表。
    3、QJsonArray可以与QVariantList进行转换。您可以使用size()、insert()和removeAt()查询条目的数量,并使用标准C++迭代器模式对其内容进行迭代。
    4、QJsonArray是一个隐式共享类,只要没有修改,它就与创建它的文档共享数据。
    5、您可以通过QJsonDocument将数组转换为基于文本的JSON。

    构建

    1、初始化列表

    QJsonArray array({1});
    QJsonArray array2({"zhouyi" ,"zhouer"});
    
    • 1
    • 2

    2、动态初始化

    QJsonArray array;
    array.append(2);
    array.append(QJsonObject({ { "name", "XiaoMing" }, { "age", 25 } }));
    array.insert(0, "XiaoTian");
    qDebug().noquote() << "111111111111111111111111" << QJsonDocument(array).toJson();
    
    • 1
    • 2
    • 3
    • 4
    • 5

    输出:

    111111111111111111111111 [
        "XiaoTian",
        2,
        {
            "age": 25,
            "name": "XiaoMing"
        }
    ]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    3.从QStringList和QVarient转换成QJsonArray

    static QJsonArray fromStringList(const QStringList &list);
    static QJsonArray fromVariantList(const QVariantList &list);
    
    QJsonArray array;
    QStringList str;
    str << "1" << "2" << "3" << "4" << "5";
    array = QJsonArray::fromStringList(str);
    qDebug().noquote() << "111111111111111111111111" << QJsonDocument(array).toJson();
    
    QJsonArray array1;
    QVariantList list;
    QVariantMap map;
    for(int i = 0; i < 3; i++)
    {
        map.clear();
        map["zhangsan"] = QString("A_%1").arg(i);
        map["lisi"] = QString("B_%1").arg(i);
        map["wangwu"] = QString("C_%1").arg(i);
        list.append(map);
    }
    array1 = QJsonArray::fromVariantList(list);
    qDebug().noquote() << "22222222222222222222" << QJsonDocument(array1).toJson();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    输出:

    111111111111111111111111 [
        "1",
        "2",
        "3",
        "4",
        "5"
    ]
    
    2222222222222222222222 [
        {
            "lisi": "B_0",
            "wangwu": "C_0",
            "zhangsan": "A_0"
        },
        {
            "lisi": "B_1",
            "wangwu": "C_1",
            "zhangsan": "A_1"
        },
        {
            "lisi": "B_2",
            "wangwu": "C_2",
            "zhangsan": "A_2"
        }
    ]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    增、删、改、遍历

    // 增
    QJsonArray array({"zhouyi", "zhouer"});
    qDebug() << "1111111111111111" <
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    QJsonDocument

    1、QJsonDocument类提供了一种读写JSON文档的方法。

    2、QJsonDocument是一个包装完整JSON文档的类,可以从UTF-8编码的基于文本的表示以及Qt自己的二进制格式读取和写入该文档。

    3、可以使用QJsonDocument::fromJson()将JSON文档从基于文本的表示转换为QJsonDocument。toJson()将其转换回文本。解析器非常快速高效,并将JSON转换为Qt使用的二进制表示。

    4、可以使用查询解析文档的有效性!isNull()

    5、可以使用isArray()和isObject()查询文档是否包含数组或对象。可以使用array()或object()检索文档中包含的数组或对象,然后读取或操作。

    6、也可以使用fromBinaryData()或fromRawData()从存储的二进制表示创建文档。

    序列化

    QJsonDocument支持从QJsonObject和QJsonArray构造:

    QJsonDocument(const QJsonObject &object)
    QJsonDocument(const QJsonArray &array)
    
    • 1
    • 2

    或者通过set方法设置数据:

    void  setArray(const QJsonArray &array)
    void  setObject(const QJsonObject &object)
    
    • 1
    • 2

    然后,使用toJson方法序列化成QByteArray,例如:

    QJsonObject object({ { "year", "2022" }, { "month", 12 }, {"day", 6} });
    qDebug().noquote() << "3333333333333333333333" << QJsonDocument(object).toJson();
    
    • 1
    • 2

    输出:

    3333333333333333333333 {
        "day": 6,
        "month": 12,
        "year": "2022"
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    另外,toJson可以传QJsonDocument::Compact参数来获取压缩后的序列化结果,压缩的结果如下:

    qDebug().noquote() << "33" << QJsonDocument(object).toJson(QJsonDocument::Compact);
    33 {"day":6,"month":12,"year":"2022"}
    
    • 1
    • 2

    反序列化

    QJsonDocument提供了静态方法fromJson来创建QJsonDocument对象:

    // error参数用于获取转换错误时的详细错误信息
    static QJsonDocument fromJson(const QByteArray &json, QJsonParseError *error = nullptr)
    
    • 1
    • 2

    然后可以判断是否是object或者array:

    bool isArray() const
    bool isObject() const
    
    • 1
    • 2

    最后可以通过object和array方法取得QJsonObject或者QJsonArray对象:

    QJsonObject object() const
    QJsonArray array() const
    
    • 1
    • 2

    总结

    了解完上面这些内容,日常使用QJson应该没有问题了。
    博客相关的内容参考了QtCreater的帮助文档以及网上好的文档的编写,其实还有还多相关的知识没有提到,后续会有相应的补充,大家一起学习一起进步,有好的内容可以分享给我

  • 相关阅读:
    【Linux】冯诺依曼体系结构、操作系统及进程概念
    LeetCode 热题 100 | 图论(三)
    吉他 手小琴大解决方法
    整数对最小和
    文件操作和IO
    系统可用性:SRE口中的3个9,4个9...到底是个什么东西?
    Django网站开发 02.CSS层叠样式表(Cascading Style Sheets)
    【MySQL】区分:等值连接/自连接/自然连接/外连接 以及ON和Where使用
    机器学习预备知识
    QML21、常规组件Window
  • 原文地址:https://blog.csdn.net/weixin_43407577/article/details/128188293