7.1Json

JSON(JavaScrip Object Notation)是一种轻量级的数据交换格式。它基于 ECMAScript (欧洲计算机协会制定的js规范)的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。 易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。

关于上面的描述可以精简为一句话:Json是一种数据格式,和语言无关,在什么语言中都可以使用Json。基于这种通用的数据格式,一般处理两方面的任务:

1.组织数据(数据序列化),用于数据的网络传输

2.组织数据(数据序列化),写磁盘文件实现数据的持久化存储(一般以.json作为文件后缀)

Json中主要有两种数据格式:Json数组和Json对象,并且这两种格式可以交叉嵌套使用,下面依次介绍下这两种数据格式:

1. Json数组

Json数组使用 \[\] 表示,\[\]里边是元素,元素和元素之间使用逗号间隔,最后一个元素后边没有逗号,一个Json数组中支持同时存在多种不同类型的成员,包括:整形、 浮点、 字符串、 布尔类型、 json数组、 json对象、 空值-null。由此可见Json数组比起C/C++数组要灵活很多。

Json数组中的元素数据类型一致

cpp 复制代码
// 整形
[1,2,3,4,5]
// 字符串
["luffy", "sanji", "zoro", "nami", "robin"]

Json数组中的元素数据类型不一致

cpp 复制代码
[12, 13.34, true, false, "hello,world", null]

Json数组中的数组嵌套使用

cpp 复制代码
[
    ["cat", "dog", "panda", "beer", "rabbit"],
    ["北京", "上海", "天津", "重庆"],
    ["luffy", "boy", 19]
]

Json数组和对象嵌套使用

cpp 复制代码
[
    {
        "luffy":{
            "age":19,
            "father":"Monkey·D·Dragon",
            "grandpa":"Monkey D Garp",
            "brother1":"Portgas D Ace",
            "brother2":"Sabo"
        }
    }
]

2. Json对象

Json对象使用 {} 来描述,每个Json对象中可以存储若干个元素,每一个元素对应一个键值对(key:value 结构),元素和元素之间使用逗号间隔,最后一个元素后边没有逗号。对于每个元素中的键值对有以下细节需要注意:

1.键值(key)必须是字符串,位于同一层级的键值不要重复(因为是通过键值取出对应的value值)

2.value值的类型是可选的,可根据实际需求指定,可用类型包括:整形、 浮点、 字符串、 布尔类型、 json数组、 json对象、 空值-null。

使用Json对象描述一个人的信息:

cpp 复制代码
{
    "Name":"Ace",
    "Sex":"man",
    "Age":20,
    "Family":{
        "Father":"Gol·D·Roger",
        "Mother":"Portgas·D·Rouge",
        "Brother":["Sabo", "Monkey D. Luffy"]
    },
    "IsAlive":false,
    "Comment":"yyds"
}

3. 注意事项

通过上面的介绍可用看到,Json的结构虽然简单,但是进行嵌套之后就可以描述很复杂的事情,在项目开发过程中往往需要我们根据实际需求自己定义Json格式用来存储项目数据。

另外,如果需要将Json数据持久化到磁盘文件中,需要注意一个问题:在一个Json文件中只能有一个Json数组或者Json对象的根节点,不允许同时存储多个并列的根节点。下面举例说明:

错误的写法

cpp 复制代码
// test.json
{
    "name":"luffy",
    "age":19
}
{
    "user":"ace",
    "passwd":"123456"
}

错误原因:在一个Json文件中有两个并列的Json根节点(并列包含Json对象和Json对象、Json对象和Json数组、Json数组和Json数组),根节点只能有一个。

正确的写法

cpp 复制代码
// test.json
{
    "Name":"Ace",
    "Sex":"man",
    "Age":20,
    "Family":{
        "Father":"Gol·D·Roger",
        "Mother":"Portgas·D·Rouge",
        "Brother":["Sabo", "Monkey D. Luffy"]
    },
    "IsAlive":false,
    "Comment":"yyds"
}

在上面的例子中通过Json对象以及Json数组的嵌套描述了一个人的身份信息,并且根节点只有一个就是Json对象,如果还需要使用Json数组或者Json对象描述其他信息,需要将这些信息写入到其他文件中,不要和这个Json对象并列写入到同一个文件里边,切记!!!

笔记

1.json概述

json这种数据格式能够方便我们把数据组织到一起,因为在网络通信的时候,我们使用套接字通信函数,它们发送的都是一个字符串,因此我们要把要发送的数据先组织到一个字符串里,然后再把这个字符串发送给对方。

2.json数组和json对象

3.使用json过程中的注意事项

根节点数组只能有一个

4.QJsonValue类的使用

5.QJsonObject类的使用

6.QJsonArray类的使用

QJsonArray里面的数据是有序的,按照key值升序

7.QJsonDocument类的使用

8.使用json对数据序列化

默认情况下按key升序排列

9.使用json对数据反序列化

反序列化就是我们从字符串里把原始数据取出来的过程

第二步是要把读出的字符串转换为json的文档对象

代码:

cpp 复制代码
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonValue>
#include <QJsonArray>
#include <QDebug>
#include <QFile>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    QJsonDocument doc;
    if(doc.isEmpty ())
    {
        qDebug()<<"json document is empty...";

    }
    if(doc.isNull ())
    {
        qDebug()<<"json document is null...";
    }
    writeJson();
    readJson();
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::writeJson()
{
    QJsonObject obj;
    obj.insert("Name", "Ace");
    obj.insert("Sex", "man");
    obj.insert("Age", 20);
    QJsonObject subObj;
    subObj.insert("Father", "Gol·D·Roger");
    subObj.insert("Mother", "Portgas·D·Rouge");
    QJsonArray array;
    array.append("Sabo");
    array.append("Monkey D. Luffy");
    subObj.insert("Brother", array);
    obj.insert("Family", subObj);
    obj.insert("IsAlive", false);
    obj.insert("Comment", "yyds");

    QJsonDocument doc(obj);
    QByteArray json = doc.toJson();

    QFile file("d:\\ace.json");
    file.open(QFile::WriteOnly);
    file.write(json);
    file.close();


}

void MainWindow::readJson()
{
    QFile file("d:\\ace.json");
    file.open(QFile::ReadOnly);
    QByteArray json = file.readAll();
    file.close();

    QJsonDocument doc = QJsonDocument::fromJson(json);
    if(doc.isObject())
    {
        QJsonObject obj = doc.object();
        QStringList keys = obj.keys();
        for(int i=0; i<keys.size(); ++i)
        {
            QString key = keys.at(i);
            QJsonValue value = obj.value(key);
            if(value.isBool())
            {
                qDebug() << key << ":" << value.toBool();
            }
            if(value.isString())
            {
                qDebug() << key << ":" << value.toString();
            }
            if(value.isDouble())
            {
                qDebug() << key << ":" << value.toInt();
            }
            if(value.isObject())
            {
                qDebug()<< key << ":";
                // 直接处理内部键值对, 不再进行类型判断的演示
                QJsonObject subObj = value.toObject();
                QStringList ls = subObj.keys();
                for(int i=0; i<ls.size(); ++i)
                {
                    QJsonValue subVal = subObj.value(ls.at(i));
                    if(subVal.isString())
                    {
                        qDebug() << "   " << ls.at(i) << ":" << subVal.toString();
                    }
                    if(subVal.isArray())
                    {
                        QJsonArray array = subVal.toArray();
                        qDebug() << "   " << ls.at(i) << ":";
                        for(int j=0; j<array.size(); ++j)
                        {
                            // 因为知道数组内部全部为字符串, 不再对元素类型进行判断
                            qDebug() << "       " << array[j].toString();
                        }
                    }
                }
            }
        }
    }
}

详细代码:

cpp 复制代码
// ================================================================
// 文件: mainwindow.cpp
// 功能: JSON 文件的写入和读取操作
// ================================================================

#include "mainwindow.h"
// 包含 MainWindow 类的头文件,声明了类的接口

#include "ui_mainwindow.h"
// 包含 Qt Designer 生成的 UI 界面类,通过 ui 指针访问控件

#include <QJsonDocument>
// 包含 JSON 文档类
// QJsonDocument 是 JSON 数据的容器,可以表示完整的 JSON 对象或数组
// 提供:fromJson() 解析 JSON 字符串,toJson() 生成 JSON 字符串
// 提供:isObject()、isArray() 判断文档类型

#include <QJsonObject>
// 包含 JSON 对象类
// QJsonObject 表示 JSON 对象(键值对集合)
// 提供:insert() 插入键值对,value() 获取值,keys() 获取所有键名

#include <QJsonValue>
// 包含 JSON 值类
// QJsonValue 表示 JSON 中的任意值(字符串、数字、布尔、对象、数组、null)
// 提供:isBool()、isString()、isDouble()、isObject()、isArray() 判断类型
// 提供:toBool()、toString()、toInt()、toObject()、toArray() 转换类型

#include <QJsonArray>
// 包含 JSON 数组类
// QJsonArray 表示 JSON 数组(有序的值列表)
// 提供:append() 添加元素,size() 获取大小,operator[]() 访问元素

#include <QDebug>
// 包含调试输出类
// 提供 qDebug() 函数用于在控制台输出调试信息

#include <QFile>
// 包含文件操作类
// 用于读写磁盘文件,支持文本和二进制模式

// ================================================================
// MainWindow 类的构造函数
// ================================================================
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)    // 调用父类 QMainWindow 的构造函数
    , ui(new Ui::MainWindow) // 创建 UI 对象,管理界面控件
{
    ui->setupUi(this);
    // 初始化用户界面
    // 根据 .ui 文件创建所有控件并设置布局
    // 必须在构造函数中首先调用

    // ============================================================
    // 测试 QJsonDocument 的默认状态
    // ============================================================
    QJsonDocument doc;
    // 创建一个空的 JSON 文档对象
    // 默认构造的文档既不是对象也不是数组,没有任何数据

    if(doc.isEmpty())
    // 判断文档是否为空
    // isEmpty() 返回 true 的条件:
    //   1. 文档是空的(没有数据)
    //   2. 文档是 null
    //   3. 文档既不是对象也不是数组
    {
        qDebug()<<"json document is empty...";
        // 输出提示信息:文档为空
        // 因为 doc 是默认构造的,所以会执行到这里
    }

    if(doc.isNull())
    // 判断文档是否为 null
    // isNull() 返回 true 的条件:
    //   1. 文档是默认构造的(没有数据)
    //   2. 文档解析失败(fromJson() 传入无效 JSON)
    // 注意:isEmpty() 包含 isNull(),但 isNull() 更精确
    {
        qDebug()<<"json document is null...";
        // 输出提示信息:文档为 null
        // 因为 doc 是默认构造的,所以会执行到这里
    }

    // ============================================================
    // 调用写入和读取函数
    // ============================================================
    writeJson();
    // 调用 writeJson() 函数
    // 创建 JSON 数据并保存到文件 d:\ace.json

    readJson();
    // 调用 readJson() 函数
    // 从文件 d:\ace.json 读取 JSON 数据并解析输出
}

// ================================================================
// MainWindow 类的析构函数
// ================================================================
MainWindow::~MainWindow()
{
    delete ui;
    // 释放 UI 对象占用的内存
    // ui 是在构造函数中通过 new 创建的,必须手动删除
    // 防止内存泄漏
}

// ================================================================
// writeJson() - 写入 JSON 数据到文件
// ================================================================
void MainWindow::writeJson()
{
    // ============================================================
    // 1. 创建根对象
    // ============================================================
    QJsonObject obj;
    // 创建一个 JSON 对象
    // 相当于 JSON 中的 { },所有数据都是这个对象的属性

    // ============================================================
    // 2. 插入基本键值对
    // ============================================================
    obj.insert("Name", "Ace");
    // 插入字符串类型键值对
    // insert(key, value) 添加或更新键值对
    // 等价 JSON: "Name": "Ace"

    obj.insert("Sex", "man");
    // 插入字符串类型键值对
    // 等价 JSON: "Sex": "man"

    obj.insert("Age", 20);
    // 插入数字类型键值对
    // Qt 自动将 int 转换为 JSON Number
    // 等价 JSON: "Age": 20

    // ============================================================
    // 3. 创建嵌套对象
    // ============================================================
    QJsonObject subObj;
    // 创建一个子对象,作为"Family"字段的值
    // 相当于嵌套的 JSON 对象

    subObj.insert("Father", "Gol·D·Roger");
    // 插入字符串:父亲
    // 等价 JSON: "Father": "Gol·D·Roger"

    subObj.insert("Mother", "Portgas·D·Rouge");
    // 插入字符串:母亲
    // 等价 JSON: "Mother": "Portgas·D·Rouge"

    // ============================================================
    // 4. 创建 JSON 数组
    // ============================================================
    QJsonArray array;
    // 创建一个 JSON 数组
    // 相当于 JSON 中的 [ ]

    array.append("Sabo");
    // 向数组末尾添加元素
    // 数组索引从 0 开始
    // 第一个元素:"Sabo"

    array.append("Monkey D. Luffy");
    // 向数组末尾添加第二个元素
    // 第二个元素:"Monkey D. Luffy"

    subObj.insert("Brother", array);
    // 将数组插入子对象,键名为 "Brother"
    // 等价 JSON: "Brother": ["Sabo", "Monkey D. Luffy"]

    // ============================================================
    // 5. 组装完整的 JSON 对象
    // ============================================================
    obj.insert("Family", subObj);
    // 将子对象插入根对象,键名为 "Family"
    // 等价 JSON: "Family": { "Father": "...", "Mother": "...", "Brother": [...] }

    obj.insert("IsAlive", false);
    // 插入布尔类型键值对
    // 等价 JSON: "IsAlive": false

    obj.insert("Comment", "yyds");
    // 插入字符串类型键值对
    // 等价 JSON: "Comment": "yyds"

    // ============================================================
    // 6. 生成 JSON 文档
    // ============================================================
    QJsonDocument doc(obj);
    // 创建 JSON 文档,用对象 obj 初始化
    // QJsonDocument 是 JSON 数据的容器

    QByteArray json = doc.toJson();
    // 将 JSON 文档转换为字节数组
    // toJson() 默认生成格式化的 JSON(带缩进和换行)
    // 等价于:doc.toJson(QJsonDocument::Indented)
    // 
    // 其他格式选项:
    //   QJsonDocument::Indented   - 格式化(带缩进)
    //   QJsonDocument::Compact    - 紧凑(无空格换行)

    // ============================================================
    // 7. 写入文件
    // ============================================================
    QFile file("d:\\ace.json");
    // 创建文件对象
    // 路径:D 盘根目录下的 ace.json 文件
    // 注意:使用双反斜杠 \\ 或正斜杠 / 作为路径分隔符

    file.open(QFile::WriteOnly);
    // 以只写模式打开文件
    // QFile::WriteOnly 表示写入模式
    // 如果文件不存在则创建,如果存在则覆盖
    // 
    // 其他打开模式:
    //   QFile::ReadOnly    - 只读
    //   QFile::Append      - 追加
    //   QFile::Text        - 文本模式(自动转换换行符)

    file.write(json);
    // 将 JSON 字节数组写入文件
    // 写入的是格式化的 JSON 字符串

    file.close();
    // 关闭文件
    // 释放文件资源,确保数据写入磁盘
}

// ================================================================
// readJson() - 从文件读取 JSON 数据并解析
// ================================================================
void MainWindow::readJson()
{
    // ============================================================
    // 1. 读取文件
    // ============================================================
    QFile file("d:\\ace.json");
    // 创建文件对象,打开之前写入的 JSON 文件

    file.open(QFile::ReadOnly);
    // 以只读模式打开文件
    // 如果文件不存在,open() 返回 false

    QByteArray json = file.readAll();
    // 读取文件所有内容
    // readAll() 返回 QByteArray,包含文件的全部数据

    file.close();
    // 关闭文件

    // ============================================================
    // 2. 解析 JSON
    // ============================================================
    QJsonDocument doc = QJsonDocument::fromJson(json);
    // 将字节数组解析为 JSON 文档
    // fromJson() 是静态函数,解析 JSON 字符串
    // 如果解析成功,返回有效的 QJsonDocument
    // 如果解析失败,返回 null 文档

    // ============================================================
    // 3. 判断文档类型并获取根对象
    // ============================================================
    if(doc.isObject())
    // 判断文档是否为对象类型
    // 如果文档是 JSON 对象,返回 true
    // 如果文档是数组或 null,返回 false
    {
        QJsonObject obj = doc.object();
        // 获取文档中的 JSON 对象
        // 相当于获取根对象的引用

        // ============================================================
        // 4. 遍历根对象的所有键
        // ============================================================
        QStringList keys = obj.keys();
        // 获取所有键名列表
        // keys() 返回 QStringList,包含所有键名
        // 顺序不固定,取决于插入顺序

        for(int i=0; i<keys.size(); ++i)
        // 遍历所有键
        // keys.size() 返回键的数量
        // i 从 0 到 keys.size()-1
        {
            // ============================================================
            // 5. 获取每个键对应的值
            // ============================================================
            QString key = keys.at(i);
            // 获取第 i 个键名
            // keys.at(i) 返回 QString,不会复制

            QJsonValue value = obj.value(key);
            // 获取键对应的值
            // value() 返回 QJsonValue 对象
            // 如果键不存在,返回 null 值

            // ============================================================
            // 6. 根据值的类型进行不同处理
            // ============================================================

            // --- 6a. 布尔类型 ---
            if(value.isBool())
            // 判断值是否为布尔类型
            // 对应 JSON 中的 true / false
            {
                qDebug() << key << ":" << value.toBool();
                // 输出键名和布尔值
                // toBool() 将 QJsonValue 转换为 bool
                // 如果值不是布尔类型,返回 false
            }

            // --- 6b. 字符串类型 ---
            if(value.isString())
            // 判断值是否为字符串类型
            // 对应 JSON 中的 "xxx"
            {
                qDebug() << key << ":" << value.toString();
                // 输出键名和字符串值
                // toString() 将 QJsonValue 转换为 QString
                // 如果值不是字符串类型,返回空字符串
            }

            // --- 6c. 数字类型 ---
            if(value.isDouble())
            // 判断值是否为数字类型
            // 对应 JSON 中的 123 或 3.14
            // 注意:JSON 中数字统一为 double 类型
            {
                qDebug() << key << ":" << value.toInt();
                // 输出键名和整数值
                // toInt() 将 QJsonValue 转换为 int
                // 如果值是小数,会截断
                // 如果想保留小数,使用 toDouble()
            }

            // --- 6d. 嵌套对象类型 ---
            if(value.isObject())
            // 判断值是否为对象类型
            // 对应 JSON 中的 { ... }
            {
                qDebug()<< key << ":";
                // 输出键名,表示这是一个嵌套对象

                // 获取子对象
                QJsonObject subObj = value.toObject();
                // toObject() 将 QJsonValue 转换为 QJsonObject
                // 如果值不是对象类型,返回空对象

                // 获取子对象的所有键
                QStringList ls = subObj.keys();
                // 获取嵌套对象的所有键名

                // 遍历子对象的键值对
                for(int i=0; i<ls.size(); ++i)
                // 遍历所有键
                {
                    // 获取子对象的值
                    QJsonValue subVal = subObj.value(ls.at(i));
                    // 获取当前键对应的值

                    // --- 处理字符串类型 ---
                    if(subVal.isString())
                    // 判断是否为字符串
                    {
                        qDebug() << "   " << ls.at(i) << ":" << subVal.toString();
                        // 输出键和值,前面加两个空格表示缩进
                        // 表示这是嵌套对象中的属性
                    }

                    // --- 处理数组类型 ---
                    if(subVal.isArray())
                    // 判断是否为数组类型
                    // 对应 JSON 中的 [ ... ]
                    {
                        QJsonArray array = subVal.toArray();
                        // 转换为 JSON 数组

                        qDebug() << "   " << ls.at(i) << ":";
                        // 输出键名,表示这是一个数组

                        // 遍历数组元素
                        for(int j=0; j<array.size(); ++j)
                        // 遍历数组中的所有元素
                        // array.size() 返回元素个数
                        {
                            // 因为知道数组内部全部为字符串,
                            // 不再对元素类型进行判断
                            qDebug() << "       " << array[j].toString();
                            // 输出数组元素,前面加四个空格表示缩进
                            // 表示这是数组中的元素
                        }
                    }
                }
            }
        }
    }
}

Qt JSON 操作完整解析

一、代码整体功能

这段代码是一个完整的 Qt JSON 读写示例,实现了以下功能:

  1. 写入 JSON :创建包含人物信息的 JSON 对象,保存到 d:\ace.json

  2. 读取 JSON:从文件读取 JSON 数据,解析并输出所有内容


二、JSON 数据结构

生成的 JSON 文件内容

cpp 复制代码
{
    "Name": "Ace",
    "Sex": "man",
    "Age": 20,
    "IsAlive": false,
    "Comment": "yyds",
    "Family": {
        "Father": "Gol·D·Roger",
        "Mother": "Portgas·D·Rouge",
        "Brother": ["Sabo", "Monkey D. Luffy"]
    }
}

数据结构关系图

cpp 复制代码
┌─────────────────────────────────────────────────────────────────────────┐
│                         JSON 数据结构                                  │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                        │
│  根对象 (root)                                                         │
│  ├── "Name": "Ace"                     (字符串)                       │
│  ├── "Sex": "man"                      (字符串)                       │
│  ├── "Age": 20                         (数字)                         │
│  ├── "IsAlive": false                  (布尔)                         │
│  ├── "Comment": "yyds"                 (字符串)                       │
│  └── "Family": {                        (嵌套对象)                    │
│        ├── "Father": "Gol·D·Roger"     (字符串)                      │
│        ├── "Mother": "Portgas·D·Rouge" (字符串)                      │
│        └── "Brother": [                 (数组)                        │
│              ├── "Sabo"                                               │
│              └── "Monkey D. Luffy"                                   │
│            ]                                                          │
│      }                                                                 │
│                                                                        │
└─────────────────────────────────────────────────────────────────────────┘

三、核心类详解

类名 作用 关键方法
QJsonDocument JSON 文档容器(整个 JSON 数据) toJson() 生成字符串,fromJson() 解析字符串,isObject() 判断类型
QJsonObject JSON 对象(键值对集合) insert() 插入键值对,value() 获取值,keys() 获取所有键名
QJsonArray JSON 数组(有序列表) append() 添加元素,size() 获取大小,operator[]() 访问元素
QJsonValue JSON 值(任意类型) isBool(), isString(), isDouble(), isObject(), isArray() 类型判断

四、writeJson() 详细解析

执行流程

cpp 复制代码
开始
  │
  ▼
创建根对象 (QJsonObject obj)
  │
  ├─► 插入基本类型: Name, Sex, Age
  │
  ├─► 创建子对象 (QJsonObject subObj)
  │    ├─► 插入 Father, Mother
  │    ├─► 创建数组 (QJsonArray array)
  │    │    ├─► append("Sabo")
  │    │    └─► append("Monkey D. Luffy")
  │    └─► 插入数组到子对象 (Brother)
  │
  ├─► 插入子对象到根对象 (Family)
  ├─► 插入 IsAlive, Comment
  │
  ├─► 创建文档 (QJsonDocument doc(obj))
  ├─► 转换为字节数组 (doc.toJson())
  │
  └─► 写入文件 (d:\ace.json)

关键代码解析

cpp 复制代码
// 1. 创建根对象
QJsonObject obj;

// 2. 插入基本类型(字符串、数字)
obj.insert("Name", "Ace");    // 字符串
obj.insert("Age", 20);        // 数字(自动转为 JSON Number)

// 3. 创建嵌套对象
QJsonObject subObj;
subObj.insert("Father", "Gol·D·Roger");

// 4. 创建数组
QJsonArray array;
array.append("Sabo");
array.append("Monkey D. Luffy");

// 5. 数组作为值
subObj.insert("Brother", array);

// 6. 嵌套对象作为值
obj.insert("Family", subObj);

// 7. 布尔类型
obj.insert("IsAlive", false);

// 8. 生成并保存
QJsonDocument doc(obj);
QByteArray json = doc.toJson();  // 格式化的 JSON 字符串

QFile file("d:\\ace.json");
file.open(QFile::WriteOnly);
file.write(json);
file.close();

五、readJson() 详细解析

执行流程

cpp 复制代码
开始
  │
  ▼
读取文件 (d:\ace.json)
  │
  ▼
解析 JSON (QJsonDocument::fromJson)
  │
  ▼
判断是否为对象 (doc.isObject())
  │
  ├─► 获取根对象 (doc.object())
  │    │
  │    ▼
  │    获取所有键名 (obj.keys())
  │    │
  │    ▼
  │    遍历每个键
  │    │
  │    ├─► 是布尔 → 输出布尔值
  │    ├─► 是字符串 → 输出字符串
  │    ├─► 是数字 → 输出数字
  │    └─► 是对象 → 递归处理子对象
  │         │
  │         ├─► 遍历子对象键
  │         │    ├─► 字符串 → 输出
  │         │    └─► 数组 → 遍历输出元素
  │         │
  │         └─► 完成
  │
  └─► 完成

关键代码解析

cpp 复制代码
// 1. 读取文件
QFile file("d:\\ace.json");
file.open(QFile::ReadOnly);
QByteArray json = file.readAll();
file.close();

// 2. 解析 JSON
QJsonDocument doc = QJsonDocument::fromJson(json);

// 3. 判断是否为对象
if(doc.isObject())
{
    QJsonObject obj = doc.object();
    
    // 4. 获取所有键名
    QStringList keys = obj.keys();
    
    // 5. 遍历键值对
    for(int i=0; i<keys.size(); ++i)
    {
        QString key = keys.at(i);
        QJsonValue value = obj.value(key);
        
        // 6. 根据类型处理
        if(value.isBool())
        {
            qDebug() << key << ":" << value.toBool();
        }
        if(value.isString())
        {
            qDebug() << key << ":" << value.toString();
        }
        if(value.isDouble())
        {
            qDebug() << key << ":" << value.toInt();
        }
        if(value.isObject())
        {
            // 7. 处理嵌套对象
            QJsonObject subObj = value.toObject();
            // ... 遍历子对象
        }
    }
}

六、控制台输出效果

cpp 复制代码
json document is empty...
json document is null...
Name : "Ace"
Sex : "man"
Age : 20
IsAlive : false
Comment : "yyds"
Family :
   Father : "Gol·D·Roger"
   Mother : "Portgas·D·Rouge"
   Brother :
       "Sabo"
       "Monkey D. Luffy"

七、QJsonValue 类型判断方法

方法 说明 对应 JSON 类型
isBool() 是否为布尔值 true / false
isString() 是否为字符串 "xxx"
isDouble() 是否为数字 123 / 3.14
isObject() 是否为对象 { ... }
isArray() 是否为数组 [ ... ]
isNull() 是否为 null null

八、改进建议

1. 添加错误处理

cpp 复制代码
void MainWindow::writeJson()
{
    QFile file("d:\\ace.json");
    if (!file.open(QFile::WriteOnly)) {
        qDebug() << "无法打开文件:" << file.errorString();
        return;
    }
    // ... 其他代码
}

2. 使用递归函数遍历 JSON

cpp 复制代码
void printJsonValue(const QJsonValue& value, int indent = 0)
{
    QString prefix(indent * 2, ' ');
    
    if (value.isObject()) {
        qDebug() << prefix << "{";
        QJsonObject obj = value.toObject();
        for (const QString& key : obj.keys()) {
            qDebug() << prefix << "  " << key << ":";
            printJsonValue(obj.value(key), indent + 1);
        }
        qDebug() << prefix << "}";
    } else if (value.isArray()) {
        qDebug() << prefix << "[";
        QJsonArray arr = value.toArray();
        for (const QJsonValue& v : arr) {
            printJsonValue(v, indent + 1);
        }
        qDebug() << prefix << "]";
    } else {
        // 基本类型
        qDebug() << prefix << value;
    }
}

3. 使用范围 for 循环

cpp 复制代码
// 更简洁的遍历方式
for (const QString& key : obj.keys()) {
    QJsonValue value = obj.value(key);
    // 处理...
}

九、总结

cpp 复制代码
┌─────────────────────────────────────────────────────────────────────────┐
│                    JSON 操作总结                                       │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                        │
│  写入流程:                                                             │
│  QJsonObject → 插入键值对 → QJsonDocument → toJson() → 写入文件      │
│                                                                        │
│  读取流程:                                                             │
│  读取文件 → QJsonDocument::fromJson() → 判断类型 → 提取值             │
│                                                                        │
│  核心类:                                                               │
│  ├── QJsonDocument  → 文档容器                                        │
│  ├── QJsonObject    → 对象(键值对)                                  │
│  ├── QJsonArray     → 数组(有序列表)                                │
│  └── QJsonValue     → 值(任意类型)                                  │
│                                                                        │
│  类型判断顺序:                                                         │
│  isObject() → isArray() → isString() → isDouble() → isBool()          │
│                                                                        │
└─────────────────────────────────────────────────────────────────────────┘
相关推荐
江畔柳前堤7 小时前
LLM + Agent 模型效果评估:从入门到工业级体系构建的完整指南
开发语言·人工智能·自然语言处理·chatgpt·架构·json·batch
Elastic 中国社区官方博客7 小时前
跳过 mapping 爆炸:ES|QL 无需动态 mapping 即可查询无 schema JSON key
大数据·人工智能·sql·elasticsearch·搜索引擎·json·全文检索
Magic-ZYJ1 天前
HarmonyOS 调用系统文件保存器导出 JSON 与 CSV
华为·json·harmonyos·鸿蒙·独立开发者
SeaTunnel1 天前
从 JSON 到 JSONL,Apache SeaTunnel 如何解决HTTP 大数据传输的内存难题?
http·开源·json·apache·数据集成·seatunnel
++==2 天前
JSON和Python的 四种核心容器
python·json
lf13210273 天前
用 JSON Schema 管装修节点记录:从照片台账到可校验工程数据
网络·数据库·人工智能·经验分享·物联网·json·智能家居
丰锋ff3 天前
7.2Qt中Json的操作
开发语言·qt·json
bugcome_com4 天前
JWT 知识小课堂:从入门到精通,一文吃透 JSON Web Token
前端·json
ccino .4 天前
awvs_json_word.py 使用说明手册
json·word