在項目開發中,配置文件通常分為三種:ini文件、xml文件和json文件,個人認為三種文件的區別在於:ini文件記錄方便、格式簡單但不便於擴展;xml文件和json文件擴展性強,能夠記錄更復雜的配置文件,但格式相對復雜,特別是**對重復項的記錄有優勢**。因此,在選擇配置文件時,如文件內容較少,無(少)重復記錄項,可選擇ini文件,若文件內容多、邏輯層次復雜、需要重復記錄多組數據或者后期后期可能需要擴展多層關系,可選擇xml或json文件。
1.INI文件
Qt通過QSettings類讀寫ini文件(但是QSetting還可以讀取其它類型的配置文件,例如:注冊表)頭文件:QSetting.h,QSetting讀寫ini文件的步驟為:
* 通過路徑名稱打開文件並設定為ini文件格式
* 讀/寫數據
* 關閉文件,刪除句柄
Qt讀文件示例如下:

1 //打開文件並指定為ini格式 2 QSettings* configIni = new QSettings(file_path, QSettings::IniFormat); 3 QString qTemp = ""; 4 //讀指定節點的指定數據,其中“Log”為節點,save_days為具體數據項 5 logDays = configIni->value("Log/save_days").toInt(); 6 qTemp = configIni->value("Log/print_debug").toString(); 7 printDbgLog = qTemp.compare("true", Qt::CaseInsensitive) == 0 ? true : false; 8 //刪除指針,此處未關聯父對象,必須手動刪除,否則有內存泄露風險 9 delete configIni;
Qt寫文件示例如下:

1 //打開文件 2 QSettings* configIni = new QSettings(filePath, QSettings::IniFormat); 3 QString qTemp = ""; 4 //寫入數據,必須指定寫入節點和值 5 configIni->setValue("Public/remove_time", removeTime); //定時任務執行時間 6 configIni->setValue("Log/save_days", logDays); //日志保存天數 7 configIni->setValue("Log/print_debug", "true"); 8 else 9 configIni->setValue("Log/print_debug", "false"); 10 delete configIni;
2.XML文件
Qt有多種方法讀取xml文件,有人在網上總結了幾種方式,具體看這里,我使用的是DOM的方式,這種方式的有點在於理解簡單,讀寫完全按照xml文件的層級操作即可;缺點則是需要將文件完全放入內存后才可讀寫,也就是說,對於非常大的xml文件,這不是一種理想的處理方式。使用DOM方式解析xml必須包含頭文件:<QtXml/qxml.h>和 <QtXml/QDomComment>
DOM方式讀取xml文件的過程如下:
a.讀取文件內容並整體轉換成DOM結構樹存儲於內存中;
b.按結構解析節點數據;
c.清理內存
具體示例代碼:

1 //xml類型配置文件讀寫 2 bool ConfigFile::LoadXMLFile(QString file_path) 3 { 4 bool bRet = true; 5 //step1:讀文件 6 QFile file(file_path); 7 if (!file.open(QFile::ReadOnly)) 8 { 9 errMsg = QString("文件打開失敗,%1").arg(file.errorString()); 10 return false; 11 } 12 13 QString errorStr; 14 int errorLine; 15 int errorColumn; 16 17 //qml數據存儲格式 18 QDomDocument doc; 19 //step2:轉換成xml數據格式 20 if (!doc.setContent(&file, false, &errorStr, &errorLine, &errorColumn)) 21 { 22 errMsg = QString("QML解析錯誤,%1,%2,%3").arg(errorStr) 23 .arg(QString::number(errorLine)).arg(QString::number(errorColumn)); 24 file.close(); 25 return false; 26 } 27 //此時已經不需要文件句柄,可關閉 28 file.close(); 29 30 //根節點元素 31 QDomElement root = doc.documentElement(); 32 33 #pragma region "每個文件不一樣,由此處開始修改" 34 //簡單節點結構 35 QDomElement parts = root.firstChildElement("module"); 36 if (parts.isNull()) 37 { 38 bRet = false; 39 errMsg = "文件格式異常,未發現[module]節點"; 40 goto _RET; 41 } 42 else 43 { 44 //ups 45 QDomElement temp = parts.firstChildElement("ups"); 46 if (temp.isNull()) 47 { 48 bRet = false; 49 errMsg = "文件格式異常,未發現[model/ups]節點"; 50 goto _RET; 51 } 52 else 53 { 54 QString st = temp.text(); 55 if (st.compare("true") == 0) 56 modeUPS = true; 57 else 58 modeUPS = false; 59 } 60 61 62 //多重嵌套、重復結構 63 { 64 parts = root.firstChildElement("processor_monitor"); 65 if (parts.isNull()) 66 { 67 bRet = false; 68 errMsg = QString("文件格式異常,未發現[processor_monitor]節點"); 69 goto _RET; 70 } 71 else 72 { 73 //循環解析,獲取測量點數據 74 QDomElement subElement = parts.firstChildElement(); 75 while (!subElement.isNull()) 76 { 77 if (subElement.tagName().compare("processor") == 0) 78 { 79 ProcessorInfo tempValue; 80 if (!GetProcessorInfo(subElement, tempValue)) 81 { 82 bRet = false; 83 errMsg = QString("進程監控節點解析失敗,%1").arg(errMsg); 84 goto _RET; 85 } 86 else 87 vecProcessorInfo.push_back(tempValue); 88 } 89 90 subElement = subElement.nextSiblingElement(); 91 } 92 } 93 } 94 95 #pragma endregion 96 97 _RET: 98 doc.clear(); 99 return bRet; 100 }
DOM方式寫入xml文件的過程如下:
a.創建DOM結構樹根節點
b.在根節點上按層級插入數據節點
c.將內存中的DOM數據結構轉化為符合xml格式的字符串
d.將字符串寫入文件
具體示例代碼:

1 bool ConfigFile::SaveXMLFile() 2 { 3 bool bRet = true; 4 QFile file(filePath); 5 QDomDocument doc; //xml結構 6 7 //以只寫入方式打開,並且打開時清空原來內容 8 if (!file.open(QFile::WriteOnly | QFile::Truncate)) 9 { 10 errMsg = QString("文件打開失敗,%1").arg(file.errorString()); 11 return false; 12 } 13 14 //寫入xml頭部 15 QDomProcessingInstruction instruction; //添加處理命令 16 instruction = doc.createProcessingInstruction("xml", "version=\"1.0\" encoding=\"UTF-8\""); 17 doc.appendChild(instruction); 18 19 //添加根節點 20 QDomElement root = doc.createElement("root"); 21 doc.appendChild(root); 22 23 #pragma region 跟隨配置文件記錄項改變 24 QString strTemp = ""; 25 QDomText text; 26 27 //寫入model節點 28 { 29 //ups 30 QDomElement model = doc.createElement("module"); 31 QDomElement subNode = doc.createElement("ups"); 32 if (modeUPS) 33 strTemp = "true"; 34 else 35 strTemp = "false"; 36 text = doc.createTextNode(strTemp); //設置括號標簽中間的值 37 subNode.appendChild(text); 38 model.appendChild(subNode); 39 40 //process 41 subNode = doc.createElement("process"); 42 if (modeUPS) 43 strTemp = "true"; 44 else 45 strTemp = "false"; 46 text = doc.createTextNode(strTemp); //設置括號標簽中間的值 47 subNode.appendChild(text); 48 model.appendChild(subNode); 49 root.appendChild(model); 50 } 51 52 53 //寫入Processor_monitor節點數據 54 { 55 QDomElement eProcessorList = doc.createElement("processor_monitor"); 56 57 for (auto it : vecProcessorInfo) 58 { 59 QDomElement eProcessor = doc.createElement("processor"); 60 61 //name 62 QDomElement eSub = doc.createElement("name"); 63 text = doc.createTextNode(it.processorName); //設置括號標簽中間的值 64 eSub.appendChild(text); 65 eProcessor.appendChild(eSub); 66 67 //path 68 eSub = doc.createElement("path"); 69 text = doc.createTextNode(it.processroPath); //設置括號標簽中間的值 70 eSub.appendChild(text); 71 eProcessor.appendChild(eSub); 72 73 //autoStart 74 if (it.isRestart) 75 strTemp = "true"; 76 else 77 strTemp = "false"; 78 eSub = doc.createElement("autostart"); 79 text = doc.createTextNode(strTemp); //設置括號標簽中間的值 80 eSub.appendChild(text); 81 eProcessor.appendChild(eSub); 82 83 //property 84 strTemp = QString::number(it.stopProprity); 85 eSub = doc.createElement("proprity"); 86 text = doc.createTextNode(strTemp); //設置括號標簽中間的值 87 eSub.appendChild(text); 88 eProcessor.appendChild(eSub); 89 90 eProcessorList.appendChild(eProcessor); 91 } 92 93 root.appendChild(eProcessorList); 94 } 95 96 #pragma endregion 97 98 //輸出到文件 99 QTextStream out_stream(&file); 100 doc.save(out_stream, 4); //縮進4格 101 file.close(); 102 doc.clear() 103 return true; 104 }
DOM方式處理xml文件比較好理解:按照各個節點的實際從屬關系插入/讀取即可,但是對內存的使用效率偏低。
3.JSON文件
在我的項目經驗中,並沒有碰到過用json文件作為配置文件的情況,個人理解,json多用於不同程序間的數據交互,相較與xml,它的冗余信息更少,但又不會丟失數據間邏輯關系,同時便於擴展,因此,個人認為,json數據更適合作為通信數據的載體而不是配置文件。
Qt處理JSON數據的類為QJsonObject、QJsonDocument、QJsonValue、QJsonParseError,頭文件與類名相同。JSON文件的處理與XML文件類似,讀取文件的過程為:a.從文件讀取數據;b.將字符型數據轉換為JSON格式數據並存在內存;c.從內存結構中讀取數據。寫文件的過程為:a.創建內存結構;b.插入數據;c.將數據轉化為字符型數據並存儲到文本中。
以下代碼展示了創建簡單json數據的過程,最終結果QstrJson為QByteArray結構:

1 QJsonObject json; 2 json.insert("CMD", QString("GRM")); 3 json.insert("RM", macro_addr); 4 5 QJsonDocument document; 6 document.setObject(json); 7 QstrJson = document.toJson(QJsonDocument::Compact); 8 if (G_INIFILE->printDbgLog) 9 LOG(INFO) << "發包數據:" << QstrJson.toStdString();
以下代碼展示解析簡單json的過程,其中,原始數據保存在qstrRecv中

1 //解析數據 2 QJsonParseError parseJsonErr; 3 QJsonDocument document = QJsonDocument::fromJson(qstrRecv.toUtf8(), &parseJsonErr); 4 if (!(parseJsonErr.error == QJsonParseError::NoError)) 5 { 6 errMsg = QString("解析json文件錯誤,%1").arg(parseJsonErr.errorString()); 7 return false; 8 } 9 10 QJsonObject jsonObject = document.object(); 11 12 //CMD 13 QString temp = jsonObject["CMD"].toString(); 14 if (temp.compare("GRM") != 0) 15 { 16 errMsg = "收包命令錯誤"; 17 return false; 18 } 19 20 //RM 21 int addrIn = jsonObject["RM"].toInt(); 22 if (addrIn != macro_addr) 23 { 24 errMsg = "收包Macro地址錯誤"; 25 return false; 26 } 27 28 //RET 29 if (jsonObject.contains("RET")) 30 { 31 QJsonValue jsonValueList = jsonObject.value("RET"); 32 QJsonObject item = jsonValueList.toObject(); 33 34 //ERR 35 int errCode = item["ERR"].toInt(); 36 if (errCode != 0) 37 { 38 //MSG 39 QString err = item["MSG"].toString(); 40 errMsg = QString("CNC反饋錯誤,錯誤碼:%1,詳情:%2").arg(errCode).arg(err); 41 return false; 42 } 43 } 44 45 //DATA 46 if (jsonObject.contains("DATA")) 47 { 48 QJsonValue jsonValueList = jsonObject.value("DATA"); 49 QJsonObject item = jsonValueList.toObject(); 50 macro_value = item["RMV"].toDouble(); 51 }
4.總結
為了以后少造輪子,根據自己的使用經驗,我自己定義了一個配置文件讀寫類,可以讀寫ini文件和xml文件,具體如下:

#pragma once #include <qsettings.h> #include <qstring.h> #include <qdir.h> #include "qcoreapplication.h" #include <mutex> #include "DataDefine.h" #include "vector" #include <QtXml/qxml.h> #include <QtXml/QDomDocument> class CLock { private: std::mutex mux; public: CLock() {} ~CLock() {} void Lock() { mux.lock(); } void Unlock() { mux.unlock(); } }; class ConfigFile { public: ~ConfigFile(); private://禁用賦值初始化 ConfigFile(); ConfigFile(const ConfigFile&); ConfigFile& operator=(const ConfigFile&); static std::shared_ptr<ConfigFile> m_pInstance; static CLock m_lock; public: //錯誤信息 QString errMsg; //日志存儲天數(天) int logDays; //是否打印調試日志 bool printDbgLog; //定時任務執行時間 QString removeTime; public://UPS相關配置 bool modeUPS; //是否啟用UPS模塊 bool modeProcess; //是否啟用process模塊 QString supplier; //供應商 QString model; //型號 QString serialName; //com口 int shutdownPCDelay; //關閉電腦延時時間 //進程監控相關配置 std::vector<ProcessorInfo> vecProcessorInfo; private: //文件類別 int fileType; //文件路徑 QString filePath; //當前exe運行路徑 //QString iniPath; //exe目錄 QString exeDir; public: //獲取句柄,懶漢單例模式,雙重鎖,線程安全 static std::shared_ptr<ConfigFile> getInstance() { if (nullptr == m_pInstance) { m_lock.Lock(); if (nullptr == m_pInstance) { m_pInstance = std::shared_ptr<ConfigFile>(new ConfigFile); } m_lock.Unlock(); } return m_pInstance; } //文件類別 enum { INI_FILE = 0, //.ini的配置文件 XML_FILE //.xml的配置文件 }; //讀取配置文件 bool LoadConfigFile(QString file_path, int file_type); //寫入配置文件 bool SaveConfigFile(); //獲取exe所在目錄 QString GetExeDir(void); private: //ini文件讀寫操作 bool LoadIniFile(QString file_path); bool SaveIniFile(); //xml文件讀寫操作 bool LoadXMLFile(QString file_path); bool SaveXMLFile(); public://按實際配置文件寫 //獲取供應商 QString GetSupplier(); //獲取UPS型號 QString GetUPSModel(); //獲取串口名稱 QString GetSerialName(); //獲取延時時間 int GetDelayMin(); private: //讀取一個進程的參數 bool GetProcessorInfo(const QDomElement &src,ProcessorInfo &value); }; #define G_CONFIG ConfigFile::getInstance()

#include "ConfigFile.h" # pragma execution_character_set("utf-8") std::shared_ptr<ConfigFile> ConfigFile::m_pInstance = nullptr; CLock ConfigFile::m_lock; ConfigFile::ConfigFile() { //日志存儲天數 logDays = 7; //是否打印調試日志 printDbgLog = false; exeDir = QCoreApplication::applicationDirPath(); fileType = XML_FILE; } ConfigFile::ConfigFile(const ConfigFile&) { } ConfigFile::~ConfigFile() { } //讀取配置文件 bool ConfigFile::LoadConfigFile(QString file_path, int file_type) { filePath = file_path; fileType = file_type; if (file_type == INI_FILE) return LoadIniFile(file_path); else if (file_type == XML_FILE) return LoadXMLFile(file_path); else { errMsg = "文件類型設置錯誤"; return false; } return false; } //寫入配置文件 bool ConfigFile::SaveConfigFile() { if (fileType == XML_FILE) return SaveXMLFile(); else return SaveIniFile(); return false; } //ini類型配置文件讀寫 bool ConfigFile::LoadIniFile(QString file_path) { filePath = file_path; QSettings* configIni = new QSettings(file_path, QSettings::IniFormat); QString qTemp = ""; //log logDays = configIni->value("Log/save_days").toInt(); qTemp = configIni->value("Log/print_debug").toString(); printDbgLog = qTemp.compare("true", Qt::CaseInsensitive) == 0 ? true : false; //定時任務時間 removeTime = configIni->value("Public/remove_time").toString(); //UPS參數 { //供應商 supplier = configIni->value("UPS/supplier").toString(); //型號 model = configIni->value("UPS/model").toString(); //com口 serialName = configIni->value("UPS/com").toString(); //關閉電腦延時時間 shutdownPCDelay = configIni->value("UPS/shutdown_pc_delay").toInt(); } //進程參數 { } delete configIni; return true; } bool ConfigFile::SaveIniFile() { QSettings* configIni = new QSettings(filePath, QSettings::IniFormat); QString qTemp = ""; //Public configIni->setValue("Public/remove_time", removeTime); //定時任務執行時間 //Log configIni->setValue("Log/save_days", logDays); //日志保存天數 if (printDbgLog) //打印調試日志 configIni->setValue("Log/print_debug", "true"); else configIni->setValue("Log/print_debug", "false"); /* //KValue configIni->setValue("KValue/part_name", qmlK.kPartName); //零件名 configIni->setValue("KValue/prg_num", qmlK.kCurPrgNum); //程序編號 configIni->setValue("KValue/param_name", qmlK.kParamName); //被測參數名稱 configIni->setValue("KValue/standard_value", qmlK.kStandardValue); //名義值 configIni->setValue("KValue/lower_deviation", qmlK.kLowerDeviation); //下公差 configIni->setValue("KValue/upper_deviation", qmlK.kUpperDeviation); //上公差 configIni->setValue("KValue/measure_value", qmlK.kMeasureValue); //測量值 configIni->setValue("KValue/measure_time", qmlK.kMeasureTime); //測量時間 configIni->setValue("KValue/work_station", qmlK.kWorkStation); //治具 //CNC configIni->setValue("CNC/ip", cncParam.ip); //CNC IP地址 configIni->setValue("CNC/port", cncParam.port); //CNC IP地址 configIni->setValue("CNC/left_x1", cncParam.leftMain.x); //左治具主孔X軸 configIni->setValue("CNC/left_y1", cncParam.leftMain.y); //左治具主孔Y軸 configIni->setValue("CNC/left_z1", cncParam.leftMain.z); //左治具主孔Z軸 configIni->setValue("CNC/left_x2", cncParam.leftSub.x); //左治具副孔X軸 configIni->setValue("CNC/left_y2", cncParam.leftSub.y); //左治具副孔Y軸 configIni->setValue("CNC/left_z2", cncParam.leftSub.z); //左治具副孔Z軸 configIni->setValue("CNC/left_x3", cncParam.leftThird.x); //左治具溫水孔X軸 configIni->setValue("CNC/left_y3", cncParam.leftThird.y); //左治具溫水孔Y軸 configIni->setValue("CNC/left_z3", cncParam.leftThird.z); //左治具溫水孔Z軸 configIni->setValue("CNC/right_x1", cncParam.rightMain.x); //右治具主孔X軸 configIni->setValue("CNC/right_y1", cncParam.rightMain.y); //右治具主孔Y軸 configIni->setValue("CNC/right_z1", cncParam.rightMain.z); //右治具主孔Z軸 configIni->setValue("CNC/right_x2", cncParam.rightSub.x); //右治具副孔X軸 configIni->setValue("CNC/right_y2", cncParam.rightSub.y); //右治具副孔Y軸 configIni->setValue("CNC/right_z2", cncParam.rightSub.z); //右治具副孔Z軸 configIni->setValue("CNC/right_x3", cncParam.rightThird.x); //右治具溫水孔X軸 configIni->setValue("CNC/right_y3", cncParam.rightThird.y); //右治具溫水孔Y軸 configIni->setValue("CNC/right_z3", cncParam.rightThird.z); //右治具溫水孔Z軸 //Folder configIni->setValue("Folder/qml_src", qstrQMLSrc); //QML源文件地址 configIni->setValue("Folder/qml_dst", qstrQMLDst); //QML目標文件地址 //section_main configIni->setValue("Section_main/alarm_lower_limit_X", limit[0].alarmLowerLimit); configIni->setValue("Section_main/alarm_upper_limit_X", limit[0].alarmUpperLimit); configIni->setValue("Section_main/avoid_lower_limit_X", limit[0].avoidLowerLimit); configIni->setValue("Section_main/avoid_upper_limit_X", limit[0].avoidUpperLimit); configIni->setValue("Section_main/alarm_lower_limit_Y", limit[1].alarmLowerLimit); configIni->setValue("Section_main/alarm_upper_limit_Y", limit[1].alarmUpperLimit); configIni->setValue("Section_main/avoid_lower_limit_Y", limit[1].avoidLowerLimit); configIni->setValue("Section_main/avoid_upper_limit_Y", limit[1].avoidUpperLimit); configIni->setValue("Section_main/alarm_lower_limit_Z", limit[2].alarmLowerLimit); configIni->setValue("Section_main/alarm_upper_limit_Z", limit[2].alarmUpperLimit); configIni->setValue("Section_main/avoid_lower_limit_Z", limit[2].avoidLowerLimit); configIni->setValue("Section_main/avoid_upper_limit_Z", limit[2].avoidUpperLimit); //Section_sub configIni->setValue("Section_sub/alarm_lower_limit_X", limit[3].alarmLowerLimit); configIni->setValue("Section_sub/alarm_upper_limit_X", limit[3].alarmUpperLimit); configIni->setValue("Section_sub/avoid_lower_limit_X", limit[3].avoidLowerLimit); configIni->setValue("Section_sub/avoid_upper_limit_X", limit[3].avoidUpperLimit); configIni->setValue("Section_sub/alarm_lower_limit_Y", limit[4].alarmLowerLimit); configIni->setValue("Section_sub/alarm_upper_limit_Y", limit[4].alarmUpperLimit); configIni->setValue("Section_sub/avoid_lower_limit_Y", limit[4].avoidLowerLimit); configIni->setValue("Section_sub/avoid_upper_limit_Y", limit[4].avoidUpperLimit); configIni->setValue("Section_sub/alarm_lower_limit_Z", limit[5].alarmLowerLimit); configIni->setValue("Section_sub/alarm_upper_limit_Z", limit[5].alarmUpperLimit); configIni->setValue("Section_sub/avoid_lower_limit_Z", limit[5].avoidLowerLimit); configIni->setValue("Section_sub/avoid_upper_limit_Z", limit[5].avoidUpperLimit); //Section_third configIni->setValue("Section_third/alarm_lower_limit_X", limit[6].alarmLowerLimit); configIni->setValue("Section_third/alarm_upper_limit_X", limit[6].alarmUpperLimit); configIni->setValue("Section_third/avoid_lower_limit_X", limit[6].avoidLowerLimit); configIni->setValue("Section_third/avoid_upper_limit_X", limit[6].avoidUpperLimit); configIni->setValue("Section_third/alarm_lower_limit_Y", limit[7].alarmLowerLimit); configIni->setValue("Section_third/alarm_upper_limit_Y", limit[7].alarmUpperLimit); configIni->setValue("Section_third/avoid_lower_limit_Y", limit[7].avoidLowerLimit); configIni->setValue("Section_third/avoid_upper_limit_Y", limit[7].avoidUpperLimit); configIni->setValue("Section_third/alarm_lower_limit_Z", limit[8].alarmLowerLimit); configIni->setValue("Section_third/alarm_upper_limit_Z", limit[8].alarmUpperLimit); configIni->setValue("Section_third/avoid_lower_limit_Z", limit[8].avoidLowerLimit); configIni->setValue("Section_third/avoid_upper_limit_Z", limit[8].avoidUpperLimit); */ delete configIni; return true; } //xml類型配置文件讀寫 bool ConfigFile::LoadXMLFile(QString file_path) { bool bRet = true; //step1:讀文件 QFile file(file_path); if (!file.open(QFile::ReadOnly)) { errMsg = QString("文件打開失敗,%1").arg(file.errorString()); return false; } QString errorStr; int errorLine; int errorColumn; //qml數據存儲格式 QDomDocument doc; //step2:轉換成xml數據格式 if (!doc.setContent(&file, false, &errorStr, &errorLine, &errorColumn)) { errMsg = QString("QML解析錯誤,%1,%2,%3").arg(errorStr) .arg(QString::number(errorLine)).arg(QString::number(errorColumn)); file.close(); return false; } file.close(); //根節點元素 QDomElement root = doc.documentElement(); #pragma region "每個文件不一樣,由此處開始修改" //mode QDomElement parts = root.firstChildElement("module"); if (parts.isNull()) { bRet = false; errMsg = "文件格式異常,未發現[module]節點"; goto _RET; } else { //ups QDomElement temp = parts.firstChildElement("ups"); if (temp.isNull()) { bRet = false; errMsg = "文件格式異常,未發現[model/ups]節點"; goto _RET; } else { QString st = temp.text(); if (st.compare("true") == 0) modeUPS = true; else modeUPS = false; } //process temp = parts.firstChildElement("process"); if (temp.isNull()) { bRet = false; errMsg = "文件格式異常,未發現[model/process]節點"; goto _RET; } else { QString st = temp.text(); if (st.compare("true") == 0) modeProcess = true; else modeProcess = false; } } //log節點 parts = root.firstChildElement("log"); if (parts.isNull()) { bRet = false; errMsg = "文件格式異常,未發現[QML]節點"; goto _RET; } else { //save_days QDomElement temp = parts.firstChildElement("save_days"); if (temp.isNull()) { bRet = false; errMsg = "文件格式異常,未發現[log/save_days]節點"; goto _RET; } else logDays = temp.text().toInt(); //print_debug temp = parts.firstChildElement("print_debug"); if (temp.isNull()) { bRet = false; errMsg = "文件格式異常,未發現[log/print_debug]節點"; goto _RET; } else { QString ss = temp.text(); if (ss.compare("true") == 0 || ss.compare("TRUE") == 0) printDbgLog = true; else printDbgLog = false; } } //Public節點 parts = root.firstChildElement("Public"); if (parts.isNull()) { bRet = false; errMsg = QString("文件格式異常,未發現[Public]節點"); goto _RET; } else { //remote_time QDomElement temp = parts.firstChildElement("remote_time"); if (temp.isNull()) { bRet = false; errMsg = "文件格式異常,未發現[Public/remote_time]節點"; goto _RET; } else removeTime = temp.text(); } //UPS節點 parts = root.firstChildElement("UPS"); if (parts.isNull()) { bRet = false; errMsg = QString("文件格式異常,未發現[UPS]節點"); goto _RET; } else { //supplier QDomElement temp = parts.firstChildElement("supplier"); if (temp.isNull()) { bRet = false; errMsg = "文件格式異常,未發現[UPS/supplier]節點"; goto _RET; } else supplier = temp.text(); //model temp = parts.firstChildElement("model"); if (temp.isNull()) { bRet = false; errMsg = "文件格式異常,未發現[UPS/model]節點"; goto _RET; } else model = temp.text(); //serialName temp = parts.firstChildElement("serialName"); if (temp.isNull()) { bRet = false; errMsg = "文件格式異常,未發現[UPS/serialName]節點"; goto _RET; } else serialName = temp.text(); //shutdownPCDelay temp = parts.firstChildElement("shutdown_pc_delay"); if (temp.isNull()) { bRet = false; errMsg = "文件格式異常,未發現[UPS/shutdown_pc_delay]節點"; goto _RET; } else shutdownPCDelay = temp.text().toInt(); } //進程監控節點 { parts = root.firstChildElement("processor_monitor"); if (parts.isNull()) { bRet = false; errMsg = QString("文件格式異常,未發現[processor_monitor]節點"); goto _RET; } else { //循環解析,獲取測量點數據 QDomElement subElement = parts.firstChildElement(); while (!subElement.isNull()) { if (subElement.tagName().compare("processor") == 0) { ProcessorInfo tempValue; if (!GetProcessorInfo(subElement, tempValue)) { bRet = false; errMsg = QString("進程監控節點解析失敗,%1").arg(errMsg); goto _RET; } else vecProcessorInfo.push_back(tempValue); } subElement = subElement.nextSiblingElement(); } } } #pragma endregion _RET: doc.clear(); return bRet; } bool ConfigFile::SaveXMLFile() { bool bRet = true; QFile file(filePath); QDomDocument doc; //xml結構 //以只寫入方式打開,並且打開時清空原來內容 if (!file.open(QFile::WriteOnly | QFile::Truncate)) { errMsg = QString("文件打開失敗,%1").arg(file.errorString()); return false; } //寫入xml頭部 QDomProcessingInstruction instruction; //添加處理命令 instruction = doc.createProcessingInstruction("xml", "version=\"1.0\" encoding=\"UTF-8\""); doc.appendChild(instruction); //添加根節點 QDomElement root = doc.createElement("root"); doc.appendChild(root); #pragma region 跟隨配置文件記錄項改變 QString strTemp = ""; QDomText text; //寫入model節點 { //ups QDomElement model = doc.createElement("module"); QDomElement subNode = doc.createElement("ups"); if (modeUPS) strTemp = "true"; else strTemp = "false"; text = doc.createTextNode(strTemp); //設置括號標簽中間的值 subNode.appendChild(text); model.appendChild(subNode); //process subNode = doc.createElement("process"); if (modeUPS) strTemp = "true"; else strTemp = "false"; text = doc.createTextNode(strTemp); //設置括號標簽中間的值 subNode.appendChild(text); model.appendChild(subNode); root.appendChild(model); } //寫入log節點數據 { QDomElement log = doc.createElement("log"); QDomElement subNode = doc.createElement("save_days"); strTemp = QString::number(logDays); text = doc.createTextNode(strTemp); //設置括號標簽中間的值 subNode.appendChild(text); log.appendChild(subNode); subNode = doc.createElement("print_debug"); if (printDbgLog) strTemp = "true"; else strTemp = "false"; text = doc.createTextNode(strTemp); //設置括號標簽中間的值 subNode.appendChild(text); log.appendChild(subNode); root.appendChild(log); } //寫入Public節點數據 { QDomElement ePublic = doc.createElement("Public"); QDomElement eRemoveTime = doc.createElement("remote_time"); text = doc.createTextNode(removeTime); //設置括號標簽中間的值 eRemoveTime.appendChild(text); ePublic.appendChild(eRemoveTime); root.appendChild(ePublic); } //寫入UPS節點數據 { QDomElement eUPS = doc.createElement("UPS"); QDomElement eSub = doc.createElement("supplier"); text = doc.createTextNode(supplier); //設置括號標簽中間的值 eSub.appendChild(text); eUPS.appendChild(eSub); eSub = doc.createElement("model"); text = doc.createTextNode(model); //設置括號標簽中間的值 eSub.appendChild(text); eUPS.appendChild(eSub); eSub = doc.createElement("serialName"); text = doc.createTextNode(serialName); //設置括號標簽中間的值 eSub.appendChild(text); eUPS.appendChild(eSub); eSub = doc.createElement("shutdown_pc_delay"); text = doc.createTextNode(QString::number(shutdownPCDelay)); //設置括號標簽中間的值 eSub.appendChild(text); eUPS.appendChild(eSub); root.appendChild(eUPS); } //寫入Processor_monitor節點數據 { QDomElement eProcessorList = doc.createElement("processor_monitor"); for (auto it : vecProcessorInfo) { QDomElement eProcessor = doc.createElement("processor"); //name QDomElement eSub = doc.createElement("name"); text = doc.createTextNode(it.processorName); //設置括號標簽中間的值 eSub.appendChild(text); eProcessor.appendChild(eSub); //path eSub = doc.createElement("path"); text = doc.createTextNode(it.processroPath); //設置括號標簽中間的值 eSub.appendChild(text); eProcessor.appendChild(eSub); //autoStart if (it.isRestart) strTemp = "true"; else strTemp = "false"; eSub = doc.createElement("autostart"); text = doc.createTextNode(strTemp); //設置括號標簽中間的值 eSub.appendChild(text); eProcessor.appendChild(eSub); //property strTemp = QString::number(it.stopProprity); eSub = doc.createElement("proprity"); text = doc.createTextNode(strTemp); //設置括號標簽中間的值 eSub.appendChild(text); eProcessor.appendChild(eSub); eProcessorList.appendChild(eProcessor); } root.appendChild(eProcessorList); } #pragma endregion //輸出到文件 QTextStream out_stream(&file); doc.save(out_stream, 4); //縮進4格 file.close(); doc.clear(); return true; } //讀取一個進程的參數 bool ConfigFile::GetProcessorInfo(const QDomElement& src, ProcessorInfo& value) { QDomElement subElement; //name subElement = src.firstChildElement("name"); if (subElement.isNull()) { errMsg = QString("[name]參數不存在"); return false; } else value.processorName = subElement.text(); //path subElement = src.firstChildElement("path"); if (subElement.isNull()) { errMsg = QString("[path]參數不存在"); return false; } else value.processroPath = subElement.text(); //autostart subElement = src.firstChildElement("autostart"); if (subElement.isNull()) { errMsg = QString("[autostart]參數不存在"); return false; } else { QString strTemp = subElement.text(); if (strTemp.compare("true") == 0 || strTemp.compare("TRUE") == 0) value.isRestart = true; else value.isRestart = false; } //property subElement = src.firstChildElement("proprity"); if (subElement.isNull()) { errMsg = QString("[proprity]參數不存在"); return false; } else { QString strTemp = subElement.text(); value.stopProprity = strTemp.toInt(); if (value.stopProprity < 0 || value.stopProprity > 2) value.stopProprity = 2; } if (value.processorName.isEmpty()) { errMsg = QString("進程名稱為空"); return false; } if (value.processroPath.isEmpty()) { errMsg = QString("進程路徑為空"); return false; } return true; } //獲取供應商 QString ConfigFile::GetSupplier() { return supplier; } //獲取UPS型號 QString ConfigFile::GetUPSModel() { return model; } //獲取串口名稱 QString ConfigFile::GetSerialName() { return serialName; } //獲取延時時間 int ConfigFile::GetDelayMin() { return shutdownPCDelay; } QString ConfigFile::GetExeDir(void) { return exeDir; }
此類采用單例模式,可供多線程是使用,同時,添加了個人認為很又必要的一些內容。