一、寫入:
簡介
介紹使用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文件並輸出里面的數據。