QT_JSON文件操作

QT_JSON 文件操作

文章目录

  • [QT_JSON 文件操作](#QT_JSON 文件操作)
    • [一、JSON 概述](#一、JSON 概述)
      • [1.1 JSON 的基本语法](#1.1 JSON 的基本语法)
      • [1.2 一个完整的 JSON 示例](#1.2 一个完整的 JSON 示例)
    • [二、Qt 中处理 JSON 的常用类](#二、Qt 中处理 JSON 的常用类)
      • [2.1 QJsonValue 的类型判断与转换](#2.1 QJsonValue 的类型判断与转换)
    • [三、QT 写入 .json 文件](#三、QT 写入 .json 文件)
      • [3.1 完整示例:`wjsonfile.h`](#3.1 完整示例:wjsonfile.h)
      • [3.2 完整示例:写入实现](#3.2 完整示例:写入实现)
      • [3.3 紧凑格式与缩进格式](#3.3 紧凑格式与缩进格式)
    • [四、QT 读取 .json 配置文件](#四、QT 读取 .json 配置文件)
      • [4.1 完整示例:读取实现](#4.1 完整示例:读取实现)
      • [4.2 完整示例:`main.cpp`](#4.2 完整示例:main.cpp)
    • 五、补充:日常开发常用技巧
      • [5.1 使用 `value()` 判断节点是否存在](#5.1 使用 value() 判断节点是否存在)
      • [5.2 解析带中文的 JSON](#5.2 解析带中文的 JSON)
      • [5.3 修改已有 JSON 并写回](#5.3 修改已有 JSON 并写回)
      • [5.4 删除某个键](#5.4 删除某个键)
      • [5.5 数组的追加与删除](#5.5 数组的追加与删除)
      • [5.6 遍历 JSON 对象的所有键](#5.6 遍历 JSON 对象的所有键)
      • [5.7 JSON 与 QVariant 互转(用于更灵活的数据)](#5.7 JSON 与 QVariant 互转(用于更灵活的数据))
      • [5.8 常见解析错误排查](#5.8 常见解析错误排查)
    • [六、JSON vs INI 对比](#六、JSON vs INI 对比)
    • 七、综合json写入读取案例
    • 八、注意事项与建议

一、JSON 概述

JSON(JavaScript Object Notation,JavaScript 对象表示法)是一种轻量级的数据交换格式,易于阅读和编写,可以在很多种语言之间进行数据交换,同时也易于机器解析和生成,并有效地提升网络传输效率。它采用完全独立于编程语言的文本格式来存储和表示数据,简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。JSON 文件的扩展名是 .json

JSON 使用场景:配置文件、序列化、定义接口。它是用于存储和交换文本信息的语法,类似 XML,但比 XML 更小、更快、更加容易解析。C 语言、C++ 语言、Python、PHP 等等都支持 JSON。

1.1 JSON 的基本语法

JSON 主要由以下两种结构组成:

  • 对象(Object){ "键": "值", ... },键值对的无序集合;
  • 数组(Array)[值1, 值2, ...],值的有序列表。

值(Value)的类型

类型 示例
字符串(String) "hello"
数字(Number) 1233.14
布尔(Boolean) true / false
空值(Null) null
对象(Object) { "key": "value" }
数组(Array) [1, 2, 3]

1.2 一个完整的 JSON 示例

json 复制代码
{
  "database": {
    "ip": "192.168.1.189",
    "port": 8080,
    "user": "root",
    "pwd": "root@123"
  },
  "notice": {
    "version": "5.6",
    "datetime": "2026.08.13 22:37",
    "enabled": true
  },
  "servers": [
    { "ip": "192.168.1.100", "name": "主服务器" },
    { "ip": "192.168.1.101", "name": "备份服务器" }
  ]
}

注意 :JSON 中字符串必须使用双引号 ",不能用单引号;键名也必须用双引号包裹;对象和数组之间用逗号分隔,最后一个元素后不能加逗号。


二、Qt 中处理 JSON 的常用类

Qt 提供了一组类用于读写和解析 JSON,主要包含:

说明
QJsonDocument 表示整个 JSON 文档,负责解析、生成与格式转换
QJsonObject 表示 JSON 对象(键值对集合)
QJsonArray 表示 JSON 数组
QJsonValue 表示 JSON 值(可保存任意上述类型)
QJsonParseError 解析错误信息,用于捕获解析失败原因

2.1 QJsonValue 的类型判断与转换

cpp 复制代码
QJsonValue value;
value.isString();   // 是否为字符串
value.isDouble();   // 是否为数字
value.isBool();     // 是否为布尔
value.isArray();    // 是否为数组
value.isObject();   // 是否为对象
value.isNull();     // 是否为 null

value.toString();   // 转为 QString
value.toInt();      // 转为 int
value.toDouble();   // 转为 double
value.toBool();     // 转为 bool
value.toArray();    // 转为 QJsonArray
value.toObject();   // 转为 QJsonObject

三、QT 写入 .json 文件

使用 QJsonDocument 将内存中的对象/数组序列化为文本,再写入 .json 文件。

3.1 完整示例:wjsonfile.h

cpp 复制代码
#ifndef WJSONFILE_H
#define WJSONFILE_H

#include <QString>

void WriteJsonFile();   // 写入 JSON 文件
void ReadJsonFile();    // 读取 JSON 文件

#endif // WJSONFILE_H

3.2 完整示例:写入实现

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

void WriteJsonFile()
{
    // 1. 构造最外层 JSON 对象
    QJsonObject rootObj;

    // 2. 构造 database 子对象
    QJsonObject dbObj;
    dbObj.insert("ip", "192.168.1.189");
    dbObj.insert("port", 8080);          // 数字类型
    dbObj.insert("user", "root");
    dbObj.insert("pwd", "root@123");
    rootObj.insert("database", dbObj);

    // 3. 构造 notice 子对象
    QJsonObject noticeObj;
    noticeObj.insert("version", "5.6");
    noticeObj.insert("datetime", "2026.08.13 22:37");
    noticeObj.insert("enabled", true);   // 布尔类型
    rootObj.insert("notice", noticeObj);

    // 4. 构造 servers 数组
    QJsonArray serverArray;
    QJsonObject server1;
    server1.insert("ip", "192.168.1.100");
    server1.insert("name", "主服务器");
    QJsonObject server2;
    server2.insert("ip", "192.168.1.101");
    server2.insert("name", "备份服务器");
    serverArray.append(server1);
    serverArray.append(server2);
    rootObj.insert("servers", serverArray);

    // 5. 将 QJsonObject 转为 QJsonDocument
    QJsonDocument doc(rootObj);

    // 6. 写入文件
    QFile file("MySQLFiles.json");
    if (!file.open(QIODevice::WriteOnly)) {
        qWarning() << "无法打开文件进行写入:" << file.errorString();
        return;
    }
    file.write(doc.toJson());   // toJson() 生成紧凑格式
    file.close();

    qDebug() << "JSON 文件写入完成";
}

3.3 紧凑格式与缩进格式

toJson() 默认生成紧凑格式(无缩进,体积小)。若希望文件更易读,可指定缩进格式:

cpp 复制代码
// 紧凑格式(默认)
file.write(doc.toJson());

// 带缩进的格式,方便人工阅读
file.write(doc.toJson(QJsonDocument::Indented));

四、QT 读取 .json 配置文件

读取时先用 fromJson() 解析文本得到 QJsonDocument,再取对象/数组逐层读取。

4.1 完整示例:读取实现

cpp 复制代码
#include "wjsonfile.h"
#include <QJsonObject>
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonParseError>
#include <QFile>
#include <QDebug>

void ReadJsonFile()
{
    // 1. 读取文件内容
    QFile file("MySQLFiles.json");
    if (!file.open(QIODevice::ReadOnly)) {
        qWarning() << "无法打开文件进行读取:" << file.errorString();
        return;
    }
    QByteArray data = file.readAll();
    file.close();

    // 2. 解析 JSON 并捕获错误
    QJsonParseError parseError;
    QJsonDocument doc = QJsonDocument::fromJson(data, &parseError);
    if (parseError.error != QJsonParseError::NoError) {
        qWarning() << "JSON 解析失败:" << parseError.errorString()
                   << "偏移位置:" << parseError.offset;
        return;
    }

    // 3. 取得最外层对象
    QJsonObject rootObj = doc.object();

    // 4. 读取 database 子对象
    QJsonObject dbObj = rootObj.value("database").toObject();
    QString ip = dbObj.value("ip").toString();
    int port = dbObj.value("port").toInt();
    QString user = dbObj.value("user").toString();
    QString pwd = dbObj.value("pwd").toString();

    // 5. 读取 notice 子对象
    QJsonObject noticeObj = rootObj.value("notice").toObject();
    QString version = noticeObj.value("version").toString();
    QString datetime = noticeObj.value("datetime").toString();
    bool enabled = noticeObj.value("enabled").toBool();

    qDebug() << "读取 JSON 配置文件参数选项如下:";
    qDebug() << "数据库地址:" << ip;
    qDebug() << "数据库端口:" << port;
    qDebug() << "数据库用户:" << user;
    qDebug() << "数据库密码:" << pwd;
    qDebug() << "数据库版本:" << version;
    qDebug() << "数据库日期:" << datetime;
    qDebug() << "是否启用:" << enabled;

    // 6. 遍历 servers 数组
    QJsonArray serverArray = rootObj.value("servers").toArray();
    for (int i = 0; i < serverArray.size(); ++i) {
        QJsonObject server = serverArray.at(i).toObject();
        QString serverIp = server.value("ip").toString();
        QString serverName = server.value("name").toString();
        qDebug() << "服务器" << i << ":" << serverName << serverIp;
    }
}

4.2 完整示例:main.cpp

cpp 复制代码
#include <QCoreApplication>
#include "wjsonfile.h"
#include <QDebug>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    // 写入 JSON 文件
    WriteJsonFile();

    // 读取 JSON 文件
    ReadJsonFile();

    return a.exec();
}

五、补充:日常开发常用技巧

5.1 使用 value() 判断节点是否存在

QJsonValueisUndefined() 可用于判断某个键是否存在(读取不存在的键时返回 undefined 值):

cpp 复制代码
QJsonObject rootObj = doc.object();
QJsonValue val = rootObj.value("database");

if (val.isUndefined()) {
    qDebug() << "未找到 database 节点";
} else if (val.isObject()) {
    QJsonObject dbObj = val.toObject();
    // ...继续处理
}

5.2 解析带中文的 JSON

fromJson() 默认按 UTF-8 解析,若源文件是 GBK/ANSI 编码需先转换:

cpp 复制代码
QByteArray data = file.readAll();
// 若文件为 GBK 编码,先转为 UTF-8
// QString str = QString::fromLocal8Bit(data);
// doc = QJsonDocument::fromJson(str.toUtf8(), &parseError);

保存时若需中文可见,可配合缩进格式一起使用 UTF-8 输出。

5.3 修改已有 JSON 并写回

先读取、修改,再整体写回:

cpp 复制代码
// 读入并解析
QFile file("MySQLFiles.json");
file.open(QIODevice::ReadOnly);
QJsonDocument doc = QJsonDocument::fromJson(file.readAll());
file.close();

// 修改端口
QJsonObject rootObj = doc.object();
QJsonObject dbObj = rootObj.value("database").toObject();
dbObj.insert("port", 9090);   // insert 会覆盖同名键
rootObj.insert("database", dbObj); // 需重新塞回修改后的子对象

// 写回
doc.setObject(rootObj);
file.open(QIODevice::WriteOnly);
file.write(doc.toJson(QJsonDocument::Indented));
file.close();

5.4 删除某个键

cpp 复制代码
QJsonObject rootObj = doc.object();
rootObj.remove("notice");     // 删除整个 notice 节点

5.5 数组的追加与删除

cpp 复制代码
QJsonArray arr = rootObj.value("servers").toArray();

// 追加
QJsonObject newServer;
newServer.insert("ip", "192.168.1.102");
newServer.insert("name", "新增服务器");
arr.append(newServer);

// 删除指定索引的元素
arr.removeAt(0);

rootObj.insert("servers", arr);

5.6 遍历 JSON 对象的所有键

cpp 复制代码
QJsonObject obj = doc.object();
QStringList keys = obj.keys();
for (const QString &key : keys) {
    QJsonValue value = obj.value(key);
    qDebug() << key << "=" << value.toString();
}

5.7 JSON 与 QVariant 互转(用于更灵活的数据)

cpp 复制代码
// QVariantMap -> JSON
QVariantMap map;
map.insert("ip", "192.168.1.1");
map.insert("port", 8080);
QJsonObject obj = QJsonObject::fromVariantMap(map);

// JSON -> QVariantMap
QVariantMap mapBack = obj.toVariantMap();

5.8 常见解析错误排查

错误码 含义
NoError 解析成功
UnterminatedObject 对象 { 未闭合
MissingNameSeparator 缺少键值分隔冒号 :
UnterminatedString 字符串未闭合
IllegalValue 非法值

解析失败时,通过 parseError.errorString()parseError.offset 可快速定位出错位置(字符偏移量)。


六、JSON vs INI 对比

维度 JSON INI
数据结构 支持对象、数组、嵌套 仅两层(节 + 键值对)
复杂度 高,适合复杂数据 低,适合简单配置
类型支持 字符串/数字/布尔/null/数组/对象 全部为字符串
可读性 好(缩进格式)
适用场景 接口数据、复杂配置、序列化 简单配置参数

七、综合json写入读取案例

dialog.cpp

cpp 复制代码
#include "dialog.h"
#include "ui_dialog.h"

#include <QMessageBox>
#include <QDebug>
#include <QFile>
#include <QJsonDocument> // JSON文件
#include <QJsonObject> // JSON对象
#include <QJsonParseError> // JSON异常捕获

Dialog::Dialog(QWidget *parent)
    : QDialog(parent)
    , ui(new Ui::Dialog)
{
    ui->setupUi(this);
}

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

// 写入JSON文件
void Dialog::on_writeBtn_clicked()
{
    // 1. 创建JSO对象
    QJsonObject mysqlInfo;
    mysqlInfo.insert("ip","192.168.1.2");
    mysqlInfo.insert("port","3110");
    mysqlInfo.insert("user","root");
    mysqlInfo.insert("pwd","root@123");
    mysqlInfo.insert("version","5.8");
    mysqlInfo.insert("datatime","2026.8.13 23:22:10");

    QJsonObject jsoninfo;
    jsoninfo.insert("code",1);
    jsoninfo.insert("dbmsg","MySql数据库配置参数");
    jsoninfo.insert("data",mysqlInfo); // 将json对象作为Json对象插入的数据值

    // 2. 创建JSON文档
    QJsonDocument jsondoc;
    jsondoc.setObject(jsoninfo);

    // 3. 创建文件
    QFile qfiles("./databasejsonfiles.json");
    if(qfiles.open(QIODevice::WriteOnly)){
        qfiles.write(jsondoc.toJson());
        qfiles.close();
        qDebug()<<"恭喜你json文件写入成功";
    }
    QMessageBox::information(this,"写入成功","恭喜你,json数据文件写入成功");
}

void Dialog::on_readBtn_clicked()
{
    QString strmsg;
    QString strjson;
    QFile qfiles("./databasejsonfiles.json");
    if(qfiles.open(QIODevice::ReadOnly)){
        strjson = qfiles.readAll();
        qfiles.close();
    }else{
        qDebug()<<"打开JSON文件失败:"<<qfiles.errorString();
        QMessageBox::warning(this,"提示","未找到JSON文件,请先点击"写入JSON文件数据信息"");
        return;
    }

    QJsonParseError jsonerror; // 返回json解析错误的时候,报告错误信息
    QJsonDocument jsondoc = QJsonDocument::fromJson(strjson.toUtf8(),&jsonerror);

    QString strtemp;
    if(!jsondoc.isEmpty() && (jsonerror.error==QJsonParseError::NoError)){
        // 只要JSON不为空,和jsonerror没有错误
        QJsonObject json = jsondoc.object();
        QJsonValue code = json.value("code");
        QJsonValue data = json.value("data");

        if(code.isUndefined() || code.toDouble()!=1 || data.isUndefined() || !data.isObject()){
            qDebug()<<"转换JSON数据错误,请重新检查";
            QMessageBox::critical(this,"错误","转换JSO你数据错误,请重新检查");
            exit(100);
        }

        // 如果没有错误,读取data数据信息
        QJsonObject databaseinfo = data.toObject();

        QJsonValue dbip = databaseinfo.value("ip");
        QJsonValue dbport = databaseinfo.value("port");
        QJsonValue dbuser = databaseinfo.value("user");
        QJsonValue dbpwd = databaseinfo.value("pwd");
        QJsonValue dbversion = databaseinfo.value("version");
        QJsonValue dbdatatime = databaseinfo.value("datatime");

        // 检查接口是否正确
        if(dbip.isUndefined() || dbport.isUndefined()|| dbuser.isUndefined()|| dbpwd.isUndefined()|| dbversion.isUndefined()|| dbdatatime.isUndefined()){
            qDebug()<<"接口错误,请重新检查";
            QMessageBox::critical(this,"错误","接口错误,请重新检查");
            exit(100);
        }

        QString strip = dbip.toString();
        int iport = dbport.toInt();
        QString strdbuser = dbuser.toString();
        QString strpwd = dbpwd.toString();
        QString strversion = dbversion.toString();
        QString strdbdatatime = dbdatatime.toString();

        if(strip.isEmpty() || strpwd.isEmpty()|| strdbuser.isEmpty()){
            qDebug()<<"此数据不能为空,请重新检查";
            QMessageBox::critical(this,"错误","此数据不能为空,请重新检查");
            exit(100);
        }

        qDebug()<<"数据库IP地址:"<<strip;
        qDebug()<<"数据库端口:"<<iport;
        qDebug()<<"数据库用户名:"<<strdbuser;
        qDebug()<<"数据库密码:"<<strpwd;
        qDebug()<<"数据库版本:"<<strversion;
        qDebug()<<"数据库时间:"<<strdbdatatime;

        // 拼接字符串
        strmsg += "数据库IP地址:" + strip + "\n";
        strmsg += "数据库端口:" + QString::number(iport,10) + "\n";
        strmsg += "数据库用户名:" + strdbuser + "\n";
        strmsg += "数据库密码:" + strpwd + "\n";
        strmsg += "数据库版本:" + strversion + "\n";
        strmsg += "数据库时间:" + strdbdatatime;

    }
    QMessageBox::information(this, "读取JSON配置参数", strmsg, QMessageBox::Yes);
}

效果

八、注意事项与建议

  1. 解析后先检查错误 :始终使用 QJsonParseError 检查 fromJson() 的结果,避免空文档引发崩溃。
  2. 字符串双引号:手写 JSON 时键名和字符串值必须用双引号,且结尾元素后不能有逗号。
  3. 类型匹配 :读取时用 toInt() / toBool() 等方法,注意写入时类型要与读取一致(如端口写数字则读用 toInt())。
  4. 文件编码:统一使用 UTF-8,避免中文乱码。
  5. 路径处理 :正式项目建议使用 QCoreApplication::applicationDirPath() + "/config/xxx.json" 指定绝对路径。
  6. 数据校验:读取后应对关键字段做合法性校验(如端口范围、非空判断),防止配置文件被误改导致运行时异常。
相关推荐
老赵的博客1 小时前
可维护性 可扩展性 可复用性
开发语言·c++
sibylyue1 小时前
工作流表单和流程设计前端
开发语言·javascript·开源
一个游离的指针1 小时前
JS中的对象的相关概念
开发语言·javascript·原型模式
jaysee-sjc2 小时前
【JavaWeb】Tlias智能学习辅助系统|后端Web实战(登录认证)
java·开发语言·前端·学习·mybatis
淡海水2 小时前
C#与常用数据结构源码剖析-全篇导览
开发语言·数据结构·unity·面试·职场和发展·c#
问天_观心2 小时前
python之uv库的学习
开发语言·python
郑州光合科技余经理2 小时前
餐饮预定系统架构拆解:订单链路、权限组织与私有化源码交付
java·开发语言·前端·数据库·人工智能·系统架构·php
在世修行2 小时前
从零打造 C# 工业视觉检测系统(十五):项目打包部署与进阶展望
开发语言·c#·视觉检测
Nebula_g2 小时前
JavaSE基础语法:特殊类(特殊情景下的设计模式)
java·开发语言·设计模式