Qt使用Json的项目实践
作者:小瑞的学习笔记
JSON介绍
Qt支持处理JSON数据。JSON是一种对源自Javascript的对象数据进行编码的格式,但现在被广泛用作互联网上的数据交换格式。
Qt中的JSON支持提供了一个易于使用的C++API来解析、修改和保存JSON数据。它还支持以二进制格式保存数据,这种格式可以直接“mmap”,并且访问速度非常快。
主要使用的类
Json 类 | 介绍 |
---|---|
QJsonDocument | 它封装了一个完整的 JSON 文档,并且可以从 UTF-8 编码的基于文本的表示以及 Qt 自己的二进制格式读取和写入该文档。 |
QJsonArray | JSON 数组是一个值列表。可以通过从数组中插入和删除 QJsonValue 来操作该列表。 |
QJsonObject | JSON 对象是键值对的列表,其中键是唯一的字符串,值由 QJsonValue 表示。 |
QJsonValue | 该类封装了 JSON 支持的数据类型。 |
QJsonValue
在 Qt 中 QJsonValue
可以封装的基础数据类型有六种(和 Json 支持的类型一致),分别为:
- 布尔类型:QJsonValue::Bool
- 浮点类型(包括整形): QJsonValue::Double
- 字符串类型: QJsonValue::String
- Json 数组类型: QJsonValue::Array
- Json 对象类型:QJsonValue::Object
- 空值类型: QJsonValue::Null
这些类型可以通过 QJsonValue 的构造函数被封装为一个类对象:
// Json对象 QJsonValue(const QJsonObject &o); // Json数组 QJsonValue(const QJsonArray &a); // 字符串 QJsonValue(const char *s); QJsonValue(QLatin1String s); QJsonValue(const QString &s); // 整形 and 浮点型 QJsonValue(qint64 v); QJsonValue(int v); QJsonValue(double v); // 布尔类型 QJsonValue(bool b); // 空值类型 QJsonValue(QJsonValue::Type type = Null);
如果我们得到一个 QJsonValue
对象,如何判断内部封装的到底是什么类型的数据呢?这时候就需要调用相关的判断函数了,具体如下:
// 是否是Json数组 bool isArray() const; // 是否是Json对象 bool isObject() const; // 是否是布尔类型 bool isBool() const; // 是否是浮点类型(整形也是通过该函数判断) bool isDouble() const; // 是否是空值类型 bool isNull() const; // 是否是字符串类型 bool isString() const; // 是否是未定义类型(无法识别的类型) bool isUndefined() const;
通过判断函数得到对象内部数据的实际类型之后,如果有需求就可以再次将其转换为对应的基础数据类型,对应的 API 函数如下:
// 转换为Json数组 QJsonArray toArray(const QJsonArray &defaultValue) const; QJsonArray toArray() const; // 转换为布尔类型 bool toBool(bool defaultValue = false) const; // 转换为浮点类型 double toDouble(double defaultValue = 0) const; // 转换为整形 int toInt(int defaultValue = 0) const; // 转换为Json对象 QJsonObject toObject(const QJsonObject &defaultValue) const; QJsonObject toObject() const; // 转换为字符串类型 QString toString() const; QString toString(const QString &defaultValue) const;
QJsonObject
QJsonObject
封装了 Json
中的对象,在里边可以存储多个键值对,为了方便操作,键值为字符串类型,值为 QJsonValue
类型。
- 如何创建空的 Json 对象
QJsonObject::QJsonObject(); // 构造空对象
- 将键值对添加到空对象中
iterator QJsonObject::insert(const QString &key, const QJsonValue &value);
- 获取对象中键值对个数
int QJsonObject::count() const; int QJsonObject::size() const; int QJsonObject::length() const;
- 通过 key 得到 value
QJsonValue QJsonObject::value(const QString &key) const; // utf8 QJsonValue QJsonObject::value(QLatin1String key) const; // 字符串不支持中文 QJsonValue QJsonObject::operator[](const QString &key) const; QJsonValue QJsonObject::operator[](QLatin1String key) const;
- 删除键值对
void QJsonObject::remove(const QString &key); QJsonValue QJsonObject::take(const QString &key); // 返回key对应的value值
- 通过 key 进行查找
iterator QJsonObject::find(const QString &key); bool QJsonObject::contains(const QString &key) const;
遍历,方式有三种:
- 使用相关的迭代器函数
- 使用 [] 的方式遍历,类似于遍历数组,[] 中是键值
- 先得到对象中所有的键值,在遍历键值列表,通过 key 得到 value 值
QStringList QJsonObject::keys() const;
QJsonDocument
- 它封装了一个完整的
JSON
文档,并且可以从 UTF-8 编码的基于文本的表示以及 Qt 自己的二进制格式读取和写入该文档。 QJsonObject
和QJsonArray
这两个对象中的数据是不能直接转换为字符串类型的,如果要进行数据传输或者数据的持久化,操作的都是字符串类型而不是QJsonObject
或者QJsonArray
类型,我们需要通过一个Json
文档类进行二者之间的转换。
下面依次介绍一下这两个转换流程应该如何操作:
1. QJsonObject 或者 QJsonArray ===> 字符串
- 创建 QJsonDocument 对象
QJsonDocument::QJsonDocument(const QJsonObject &object); QJsonDocument::QJsonDocument(const QJsonArray &array);
可以看出,通过构造函数就可以将实例化之后的 QJsonObject 或者 QJsonArray 转换为 QJsonDocument 对象了。
- 将文件对象中的数据进行序列化
// 二进制格式的json字符串 QByteArray QJsonDocument::toBinaryData() const; // 文本格式 QByteArray QJsonDocument::toJson(JsonFormat format = Indented) const;
通过调用 toxxx() 方法就可以得到文本格式或者二进制格式的 Json 字符串了。
- 使用得到的字符串进行数据传输,或者磁盘文件持久化
2. 字符串 ===> QJsonObject 或者 QJsonArray
一般情况下,通过网络通信或者读磁盘文件就会得到一个 Json 格式的字符串,如果想要得到相关的原始数据就需要对字符串中的数据进行解析,具体解析流程如下:
- 将得到的 Json 格式字符串通过 QJsonDocument 类的静态函数转换为 QJsonDocument 类对象
[static] QJsonDocument QJsonDocument::fromBinaryData(const QByteArray &data, DataValidation validation = Validate); // 参数文件格式的json字符串 [static] QJsonDocument QJsonDocument::fromJson(const QByteArray &json, QJsonParseError *error = Q_NULLPTR);
- 将文档对象转换为 json 数组 / 对象
// 判断文档对象中存储的数据是不是数组 bool QJsonDocument::isArray() const; // 判断文档对象中存储的数据是不是json对象 bool QJsonDocument::isObject() const // 文档对象中的数据转换为json对象 QJsonObject QJsonDocument::object() const; // 文档对象中的数据转换为json数组 QJsonArray QJsonDocument::array() const;
- 通过调用 QJsonArray , QJsonObject 类提供的 API 读出存储在对象中的数据。
关于 Qt 中 Json 数据对象以及字符串之间的转换的操作流程是固定的,我们在编码过程中只需要按照上述模板处理即可,相关的操作是没有太多的技术含量可言的。
实战
1. 手动写Json文件
注意:[…] 中是数组元素,{…}中是Json对象
2. 实现程序(从Json文件中读取数据,更改Json文件中的数据)
mainwindow.h
class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); QVector<struct Animal> readJson();// 读取Json文件 bool changeDate();// 改变Json文件中的数据 private: Ui::MainWindow *ui; }; struct Food{ QString stapleFood; QString meat; }; struct Animal{ QString name; int age; QVector<QString> eatTimeArr; struct Food food; };
mainwindow.cpp
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); changeDate(); readJson(); } MainWindow::~MainWindow() { delete ui; } // 增加数据直接在手动修改Json文件 // 查数据(已知Json数据格式的情况下):将Json中所有animal类保存到vector中全部返回 QVector<struct Animal> MainWindow::readJson() { QFile file("D:\\Qt\\homework\\text01\\studyJson.json"); bool ret = file.open(QFile::ReadOnly); QByteArray bytes = file.readAll();// 把文件中所有数据读取出来 QJsonDocument doc = QJsonDocument::fromJson(bytes);// 将读出的数据保存为Json文档 QJsonArray groupArr = doc.array();// 获取数组 QVector<struct Animal> ans;// 用于保存获取到的数据 for(int i = 0; i < groupArr.size(); i++) { QJsonObject obj = groupArr.at(i).toObject();// 把数组中每一个数据都转化为 QJsonObject struct Animal animal; animal.name = obj.value("name").toString(); animal.age = obj.value("age").toInt(); // eatTime 对应的值为一个数组 QJsonArray foodArr = obj.value("eatTime").toArray(); for(int i = 0; i < foodArr.size(); i++) { animal.eatTimeArr.push_back(foodArr.at(i).toString()); } // food 对应的值为一个 QJsonObject 类型 QJsonObject subObj = obj.value("food").toObject(); animal.food.stapleFood = subObj.value("stapleFood").toString(); animal.food.meat = subObj.value("meat").toString(); ans.push_back(animal);// 将获取到的数据加入容器中 qDebug() << "name =" << animal.name << "age =" << animal.age << "eatTime =" << animal.eatTimeArr[0] << animal.eatTimeArr[1] << animal.eatTimeArr[2] << "food.stapleFood =" << animal.food.stapleFood << "food.meat =" << animal.food.meat; } return ans; } // 改数据:从studyJson.json读取数据并且富贵的年龄改为10岁 bool MainWindow::changeDate() { // 打开文件 QFile file("D:\\Qt\\homework\\text01\\studyJson.json"); file.open(QIODevice::ReadWrite); QByteArray bytes = file.readAll();// 读取文件所有内容 file.close(); QJsonDocument doc = QJsonDocument::fromJson(bytes);// 将读出的数据保存为Json文档 QJsonArray groupArr = doc.array();// 获取数组 QJsonObject obj = groupArr.at(0).toObject();// 获取数组中第一个元素 // 判断 "age"节点是否存在 if(obj.contains("age")){ obj["age"] = 10;// 将数组第一个元素中的年龄改变 // 此时我们新建一个数组,把更新好的元素加入数组,并且把之前数组中没有改变的元素加入 QJsonArray arr; arr.append(obj); arr.append(groupArr.at(1).toObject()); // 保存至Json文档 注意:调用setArray后,先会把之前保存所有的数据清除,然后再保存新的数据 doc.setArray(arr); } // 把最新数据写入QIODevice::Truncate file.open(QFile::WriteOnly|QFile::Truncate); file.seek(0);// 使写入位置为起始位置 file.write(doc.toJson()); }
打印调试信息
执行changeDate()后,Json文件改变
这里需要注意:如果用Json自己写入文件,他所有数据会根据key的字典序排列
到此这篇关于Qt使用Json的项目实践的文章就介绍到这了,更多相关Qt使用Json内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!