QT中json读写
一、写入:
简介
介绍使用Qt读写JSON文件。如果你对JSON不是很了解,请阅读我之前的一篇文章json简介。
使用的开发环境为:
Qt 5.12.0+Deepin 15.8
在Qt中与JSON相关的类有以下几个,Q=QJsonDocument,QJsonArray,QJsonObject,QJsonParseError,QJsonValue。
其中QJsonDocument类提供了读写JSON文档的方式,我们可以通过该类的方法QJsonDocument::fromJson()将一个JSON文档转换成QJsonDocument类,或者通过QJsonDocument::toJson()和QJsonDocument::toBinaryData()函数将一个QJsonDocument类转换为QByteArray,这样我们就可以很轻松地将其写入文件。
QJsonArray封装了JSON中的数组。
QJsonObject封装了JSON中的对象。
QJsonValue封装了JSON中的值。
QJsonParseError 用于报告JSON解析中的错误类型。
使用QJsonObject简单演示
首先,我们使用Qt creator创建一个Qt Console Application项目,项目名称位置可随意。
修改main.cpp中的代码如下所示
1 #include <QJsonArray> 2 #include <QJsonDocument> 3 #include <QJsonObject> 4 #include <QJsonParseError> 5 #include <QJsonValue> 6 #include <QString> 7 #include <QDebug> 8 #include <QFile> 9 #include <QDateTime> 10 #include <QDir> 11 12 int main(int argc, char *argv[]) { 13 // 以读写方式打开主目录下的1.json文件,若该文件不存在则会自动创建 14 QFile file(QDir::homePath() + "/1.json"); 15 if(!file.open(QIODevice::ReadWrite)) { 16 qDebug() << "File open error"; 17 } else { 18 qDebug() <<"File open!"; 19 } 20 // 使用QJsonObject对象插入键值对。 21 QJsonObject jsonObject; 22 jsonObject.insert("name", "tom"); 23 jsonObject.insert("age", "18"); 24 jsonObject.insert("time", QDateTime::currentDateTime().toString()); 25 26 // 使用QJsonDocument设置该json对象 27 QJsonDocument jsonDoc; 28 jsonDoc.setObject(jsonObject); 29 30 // 将json以文本形式写入文件并关闭文件。 31 file.write(jsonDoc.toJson()); 32 file.close(); 33 34 qDebug() << "Write to file"; 35 return 0; 36 }
之后打开你的终端(linux环境下), 会看到我们的程序在主目录下生成了一个1.json的文件。然后查看下里面的内容。
不知道你有没有注意到,我们在jsonObject中插入键值对的顺序和文件中的键值对顺序不太一样,这是因为JSON中的object本身是指无序的键值对,它不能确保我们插入的顺序和实际保存的数据顺序一致。如果你的数据需要顺序一致,考虑JSON中的array,array是值的有序列表。
简单使用QJsonArray
修改main.cpp中的代码如下,注:该代码会清空主目录先1.json的原有内容,如果你想保留原有的文件内容,请备份或者修改写入的文件名。
1 #include <QJsonArray> 2 #include <QJsonDocument> 3 #include <QJsonObject> 4 #include <QJsonParseError> 5 #include <QJsonValue> 6 #include <QString> 7 #include <QDebug> 8 #include <QFile> 9 #include <QDateTime> 10 #include <QDir> 11 12 int main(int argc, char *argv[]) { 13 // 以读写方式打开主目录下的1.json文件,若该文件不存在则会自动创建 14 QFile file(QDir::homePath() + "/1.json"); 15 if(!file.open(QIODevice::ReadWrite)) { 16 qDebug() << "File open error"; 17 } else { 18 qDebug() <<"File open!"; 19 } 20 21 // 清空文件中的原有内容 22 file.resize(0); 23 24 // 使用QJsonArray添加值,并写入文件 25 QJsonArray jsonArray; 26 jsonArray.append("name"); 27 jsonArray.append(18); 28 jsonArray.append(QDateTime::currentDateTime().toString()); 29 30 QJsonDocument jsonDoc; 31 jsonDoc.setArray(jsonArray); 32 33 file.write(jsonDoc.toJson()); 34 file.close(); 35 36 qDebug() << "Write to file"; 37 return 0; 38 }
这次文件中的数据顺序,和我们扩展JSON数组中的顺序是一致的。
稍微复杂的例子
我们注意到JSON中的值可以是字符串、数组、对象、数字等,因此我们试试结合使用一下。
1 #include <QJsonArray> 2 #include <QJsonDocument> 3 #include <QJsonObject> 4 #include <QJsonParseError> 5 #include <QJsonValue> 6 #include <QString> 7 #include <QDebug> 8 #include <QFile> 9 #include <QDateTime> 10 #include <QDir> 11 #include <QThread> 12 13 int main(int argc, char *argv[]) { 14 // 以读写方式打开主目录下的1.json文件,若该文件不存在则会自动创建 15 QFile file(QDir::homePath() + "/1.json"); 16 if(!file.open(QIODevice::ReadWrite)) { 17 qDebug() << "File open error"; 18 } else { 19 qDebug() <<"File open!"; 20 } 21 22 // 清空文件中的原有内容 23 file.resize(0); 24 25 // 使用QJsonArray添加值,并写入文件 26 QJsonArray jsonArray; 27 28 for(int i = 0; i < 3; i++) { 29 QJsonObject jsonObject; 30 jsonObject.insert("name", QString::number(i+1)); 31 jsonObject.insert("age", i+18); 32 jsonObject.insert("time", QDateTime::currentDateTime().toString()); 33 jsonArray.append(jsonObject); 34 QThread::sleep(2); 35 } 36 37 QJsonObject jsonObject; 38 jsonObject.insert("number", jsonArray.size()); 39 jsonArray.append(jsonObject); 40 41 QJsonDocument jsonDoc; 42 jsonDoc.setArray(jsonArray); 43 44 file.write(jsonDoc.toJson()); 45 file.close(); 46 47 qDebug() << "Write to file"; 48 return 0; 49 }
结果如下所示
二、解析:
之前介绍了简单的示例,这次我们进行JSON文件的解析。
在你的桌面新建文件命名为test.json,内容填写如下:
1 { 2 "postsNum" : 2, 3 "posts" : [ 4 { 5 "postID" : 10086, 6 "postTitle" : "hello", 7 "postContent" : "你好啊" 8 }, 9 { 10 "postID" : 10010, 11 "postTitle" : "hi", 12 "postContent" : "大家好" 13 } 14 ] 15 }
从JSON定义来看,这是一个包含有两个键值对的对象,其中一个对象的名字是"postsNum",值是一个数字,另一键值对的名字是"posts",值是一个数组。这个数组由两个对象组成,每个对象由三个相同的键值对组成,第一个键值对名字为"postID" ,值为数字;第二个键值对名字为 "postTitle" ,值为字符串 "hello";第三个键值对名字为 "postContent" ,值为字符串。实际上,数组中的对象描述了一个简单的帖子的数据结构,这个帖子有postID、postTitle、postContent组成。
接下来我们使用Qt Creator新建一个Qt Console Application项目,名称和位置可以随意。
修改默认生成的main.cpp中的代码如下所示:
1 #include <QDir> 2 #include <QFile> 3 #include <QJsonArray> 4 #include <QJsonDocument> 5 #include <QJsonObject> 6 #include <QJsonParseError> 7 #include <QJsonValue> 8 9 #include <QSysInfo> 10 11 #include <cstdlib> 12 #include <iostream> 13 14 using std::cout; 15 16 int main( int argc, char *argv[] ) { 17 // Qt的一个宏,消除未使用变量的警告,无实际作用 18 // 定义为,#define Q_UNUSED(x) (void)x 19 Q_UNUSED( argc ); 20 Q_UNUSED( argv ); 21 22 // 如果当前操作系统为windows系统的话 23 // 修改控制台的编码为utf8,防止中文乱码 24 if ( QSysInfo::productType() == "windows" || 25 QSysInfo::productType() == "winrt" ) { 26 system( "chcp 65001" ); 27 } 28 29 cout << "当前使用的操作系统类型为:"; 30 cout << QSysInfo::productType().toStdString() << "\n"; 31 // 默认打开的文件位置为用户桌面的test.txt文件。 32 QFile file( QDir::homePath() + "/Desktop/test.json" ); 33 if ( !file.open( QIODevice::ReadWrite ) ) { 34 cout << "文件打开失败!\n"; 35 exit( 1 ); 36 } 37 cout << "文件打开成功\n"; 38 39 QJsonParseError jsonParserError; 40 QJsonDocument jsonDocument = 41 QJsonDocument::fromJson( file.readAll(), &jsonParserError ); 42 43 if ( !jsonDocument.isNull() && 44 jsonParserError.error == QJsonParseError::NoError ) { 45 cout << "文件解析成功\n"; 46 if ( jsonDocument.isObject() ) { 47 QJsonObject jsonObject = jsonDocument.object(); 48 if ( jsonObject.contains( "postsNum" ) && 49 jsonObject.value( "postsNum" ).isDouble() ) { 50 cout << "postsNum is " << jsonObject.value( "postsNum" ).toInt() 51 << "\n"; 52 } 53 54 if ( jsonObject.contains( "posts" ) && 55 jsonObject.value( "posts" ).isArray() ) { 56 QJsonArray jsonArray = jsonObject.value( "posts" ).toArray(); 57 for ( int i = 0; i < jsonArray.size(); i++ ) { 58 if ( jsonArray[ i ].isObject() ) { 59 QJsonObject jsonObjectPost = jsonArray[ i ].toObject(); 60 if ( jsonObjectPost.contains( "postID" ) && 61 jsonObjectPost.contains( "postTitle" ) && 62 jsonObjectPost.contains( "postContent" ) && 63 jsonObjectPost.value( "postID" ).isDouble() && 64 jsonObjectPost.value( "postTitle" ).isString() && 65 jsonObjectPost.value( "postContent" ) 66 .isString() ) { 67 cout << "posts[" << i << "] :\n"; 68 cout << "postID is " 69 << jsonObjectPost.value( "postID" ).toInt() 70 << "\n"; 71 cout << "postTitle is " 72 << jsonObjectPost.value( "postTitle" ) 73 .toString() 74 .toStdString() 75 << "\n"; 76 cout << "postContent is " 77 << jsonObjectPost.value( "postContent" ) 78 .toString() 79 .toStdString() 80 << "\n"; 81 } 82 } 83 } 84 } 85 } 86 } 87 88 file.close(); 89 cout << "按任意键退出程序\n"; 90 91 return 0; 92 }
这段代码也很容易理解,首先判断当前系统是否为windows,如果是的话就修改CMD编码为utf8,防止出现中文乱码,之后打开桌面上的test.json文件,解析为json文件并输出里面的数据。