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 紧凑格式与缩进格式)
- [3.1 完整示例:`wjsonfile.h`](#3.1 完整示例:
- [四、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 常见解析错误排查)
- [5.1 使用 `value()` 判断节点是否存在](#5.1 使用
- [六、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) | 123 或 3.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() 判断节点是否存在
QJsonValue 的 isUndefined() 可用于判断某个键是否存在(读取不存在的键时返回 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);
}

效果


八、注意事项与建议
- 解析后先检查错误 :始终使用
QJsonParseError检查fromJson()的结果,避免空文档引发崩溃。 - 字符串双引号:手写 JSON 时键名和字符串值必须用双引号,且结尾元素后不能有逗号。
- 类型匹配 :读取时用
toInt()/toBool()等方法,注意写入时类型要与读取一致(如端口写数字则读用toInt())。 - 文件编码:统一使用 UTF-8,避免中文乱码。
- 路径处理 :正式项目建议使用
QCoreApplication::applicationDirPath() + "/config/xxx.json"指定绝对路径。 - 数据校验:读取后应对关键字段做合法性校验(如端口范围、非空判断),防止配置文件被误改导致运行时异常。