前言
json是一种对源自Javascript的对象数据进行编码的格式,但现在广泛用于互联网上的数据交换格式。Qt5中提供了易于使用的C++ API来解析、修改和保存json数据。
Qt中提供了5个类来操作json,下面是类信息:
| 类名 | 类描述 |
|---|---|
| QJsonObject | 封装了json对象 |
| QJsonArray | 封装了json数组 |
| QJsonValue | 封装了json的值 |
| QJsonDocument | 提供了json文件读写的方式 |
| QJsonParseError | 这个类被用于在解析json报告错误 |
QJsonValue为json提供了6种基础数据类型,分别是
- bool
- double
- string
- array
- object
- null
Qt读取json文件
{
"teacher_name": "wangwu",
"teacher_age": 30,
"student": [
{
"name": "zhangsan",
"age": 12
},
{
"name": "lisi",
"age": 14
},
{
"name": "zhaoliu",
"age": 13
}
]
}
#include <QDebug>
#include <QFile>
#include <QJsonArray>
#include <QJsonObject>
#include <QJsonDocument>
struct Student {
QString strName;
int dwAge = 0;
};
struct Course
{
QString strTeacherName;
int dwTeacherAge = 0;
QVector<Student> students;
void debug() const;
};
void Course::debug() const
{
qDebug() << "teacher name is " << strTeacherName << ", age is " << dwTeacherAge;
for (const Student & curStudent : students)
{
qDebug() << "\t student name is " << curStudent.strName << ", age is " << curStudent.dwAge;
}
}
void loadJsonFile()
{
QFile loadFile("D://config.json");
if (!loadFile.open(QIODevice::ReadOnly))
{
qDebug() << "open file " << loadFile.fileName() << " failed";
return;
}
QByteArray allData = loadFile.readAll();
loadFile.close();
QJsonParseError jsonError;
QJsonDocument jsonDoc = QJsonDocument::fromJson(allData, &jsonError);
if (jsonError.error != QJsonParseError::NoError)
{
qDebug() << "parse json object failed, " << jsonError.errorString();
return;
}
QJsonObject jsonObj = jsonDoc.object();
Course curCourse;
curCourse.strTeacherName = jsonObj.value("teacher_name").toString();
curCourse.dwTeacherAge = jsonObj.value("teacher_age").toInt();
if (jsonObj.value("student").isArray())
{
QJsonArray jsonArray = jsonObj.value("student").toArray();
//对QJsonArray进行排序
std::sort(jsonArray.begin(), jsonArray.end(), [](const QJsonValue & lhs, const QJsonValue & rhs) -> bool {
return lhs.toObject().value("age").toInt() < rhs.toObject().value("age").toInt();
});
for (const QJsonValue jsonStu : jsonArray)
{
Student curStudent;
curStudent.strName = jsonStu.toObject().value("name").toString();
curStudent.dwAge = jsonStu.toObject().value("age").toInt();
curCourse.students.push_back(curStudent);
}
}
curCourse.debug();
}
-
vs2017编译运行
如果服务器传过来一个乱序的QJsonArray,我们需要自己对QJsonArray排序,可以使用上面的std::sort进行排序,程序输出结果如下:
如果把std::sort换成qSort,程序输出结果就变成了这样:
一脸懵逼,难道是Qt5中的qSort有BUG?
-
qtcreator编译运行
qtcreator直接编译报错,找不到swap(QJsonValueRef, QJsonValueRef)对应的函数,下面是报错信息:
通过这些信息发现,上面的7个重载版本都是用Q_DECLARE_SHARED包裹起来的,这个宏展开后会得到这样的代码
inline void swap(TYPE &value1, TYPE &value2) noexcept { value1.swap(value2); }我试图Q_DECLARE_SHARED(QJsonValueRef),可惜QJsonValueRef对象并没有swap成员函数。然后尝试重载一个swap函数。
void swap(QJsonValue & lhs, QJsonValue & rhs) noexcept { qSwap(lhs, rhs); }这样编译不会报错,可以输出正确的结果,但是断点调试发现,程序并没有调用到我重载的函数,也是很神奇。
Qt写入json文件
#include <QtCore/QCoreApplication>
#include <QDebug>
#include <QFile>
#include <QJsonArray>
#include <QJsonObject>
#include <QJsonDocument>
struct Student {
QString strName;
int dwAge = 0;
};
struct Course
{
QString strTeacherName;
int dwTeacherAge = 0;
QVector<Student> students;
};
Course curCourse = { "zhangsan", 40, { {"lisi", 20}, {"wangwu", 21}, {"zhaoliu", 22}, } };
void saveJsonFile()
{
QFile writeFile("D://config.json");
if (!writeFile.open(QIODevice::WriteOnly))
{
qDebug() << "open file " << writeFile.fileName() << " failed";
return;
}
QJsonObject jsonObj;
jsonObj.insert("teacher_name", curCourse.strTeacherName);
jsonObj.insert("teacher_age", curCourse.dwTeacherAge);
QJsonArray jsonArray;
for (const Student curStudent : curCourse.students)
{
QJsonObject jsonStu;
jsonStu.insert("name", curStudent.strName);
jsonStu.insert("age", curStudent.dwAge);
jsonArray.push_back(jsonStu);
}
jsonObj.insert("student", jsonArray);
QJsonDocument jsonDoc;
jsonDoc.setObject(jsonObj);
writeFile.write(jsonDoc.toJson(QJsonDocument::Compact));
writeFile.close();
}
{"student":[{"age":20,"name":"lisi"},{"age":21,"name":"wangwu"},{"age":22,"name":"zhaoliu"}],"teacher_age":40,"teacher_name":"zhangsan"}
| 枚举类型 | 字段详细描述 |
|---|---|
| QJsonDocument::Indented(默认值) | 以人类可读的方式序列化数据 |
| QJsonDocument::Compact | 以紧凑的方式序列化数据,会去除空格和换行符 |
Qt读写json二进制文件
QJsonDocument支持将json对象序列化成二进制的形式进行读写,这种方式的优点就是可以直接"mmap"更快的访问,缺点就是不易阅读。
-
写入二进制文件
//上例中的writeFile.write(jsonDoc.toJson(QJsonDocument::Compact));替换成下面这句 writeFile.write(jsonDoc.toBinaryData()); -
读取二进制文件
//QJsonParseError jsonError; //QJsonDocument jsonDoc = QJsonDocument::fromJson(allData, &jsonError); //if (jsonError.error != QJsonParseError::NoError) //{ // qDebug() << "parse json object failed, " << jsonError.errorString(); // return; //} //把上例中的代码注释掉,换成下面的代码就可以了 QJsonDocument jsonDoc = QJsonDocument::fromBinaryData(allData); if (!jsonDoc.isObject()) { qDebug() << "parse json object failed, "; return; }