在項目開發中,配置文件通常分為三種:ini文件、xml文件和json文件,個人認為三種文件的區別在於:ini文件記錄方便、格式簡單但不便於擴展;xml文件和json文件擴展性強,能夠記錄更復雜的配置文件,但格式相對復雜,特別是**對重復項的記錄有優勢**。因此,在選擇配置文件時,如文件內容較少,無(少)重復記錄項,可選擇ini文件,若文件內容多、邏輯層次復雜、需要重復記錄多組數據或者后期后期可能需要擴展多層關系,可選擇xml或json文件。
1.INI文件
Qt通過QSettings類讀寫ini文件(但是QSetting還可以讀取其它類型的配置文件,例如:注冊表)頭文件:QSetting.h,QSetting讀寫ini文件的步驟為:
* 通過路徑名稱打開文件並設定為ini文件格式
* 讀/寫數據
* 關閉文件,刪除句柄
Qt讀文件示例如下:
//打開文件並指定為ini格式 QSettings* configIni = new QSettings(file_path, QSettings::IniFormat); QString qTemp = ""; //讀指定節點的指定數據,其中“Log”為節點,save_days為具體數據項 logDays = configIni->value("Log/save_days").toInt(); qTemp = configIni->value("Log/print_debug").toString(); printDbgLog = qTemp.compare("true", Qt::CaseInsensitive) == 0 ? true : false; //刪除指針,此處未關聯父對象,必須手動刪除,否則有內存泄露風險 delete configIni;
Qt寫文件示例如下:
//打開文件 QSettings* configIni = new QSettings(filePath, QSettings::IniFormat); QString qTemp = ""; //寫入數據,必須指定寫入節點和值 configIni->setValue("Public/remove_time", removeTime); //定時任務執行時間 configIni->setValue("Log/save_days", logDays); //日志保存天數 configIni->setValue("Log/print_debug", "true"); else configIni->setValue("Log/print_debug", "false"); delete configIni;
2.XML文件
Qt有多種方法讀取xml文件,有人在網上總結了幾種方式,具體看這里,我使用的是DOM的方式,這種方式的有點在於理解簡單,讀寫完全按照xml文件的層級操作即可;缺點則是需要將文件完全放入內存后才可讀寫,也就是說,對於非常大的xml文件,這不是一種理想的處理方式。使用DOM方式解析xml必須包含頭文件:<QtXml/qxml.h>和<QtXml/QDomComment>
DOM方式讀取xml文件的過程如下:
a.讀取文件內容並整體轉換成DOM結構樹存儲於內存中;
b.按結構解析節點數據;
c.清理內存
具體示例代碼:

//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 "每個文件不一樣,由此處開始修改" //簡單節點結構 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; } //多重嵌套、重復結構 { 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; }
DOM方式寫入xml文件的過程如下:
a.創建DOM結構樹根節點
b.在根節點上按層級插入數據節點
c.將內存中的DOM數據結構轉化為符合xml格式的字符串
d.將字符串寫入文件
具體示例代碼:

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); } //寫入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; }
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結構:
QJsonObject json; json.insert("CMD", QString("GRM")); json.insert("RM", macro_addr); QJsonDocument document; document.setObject(json); QstrJson = document.toJson(QJsonDocument::Compact); if (G_INIFILE->printDbgLog) LOG(INFO) << "發包數據:" << QstrJson.toStdString();
以下代碼展示解析簡單json的過程,其中,原始數據保存在qstrRecv中

//解析數據 QJsonParseError parseJsonErr; QJsonDocument document = QJsonDocument::fromJson(qstrRecv.toUtf8(), &parseJsonErr); if (!(parseJsonErr.error == QJsonParseError::NoError)) { errMsg = QString("解析json文件錯誤,%1").arg(parseJsonErr.errorString()); return false; } QJsonObject jsonObject = document.object(); //CMD QString temp = jsonObject["CMD"].toString(); if (temp.compare("GRM") != 0) { errMsg = "收包命令錯誤"; return false; } //RM int addrIn = jsonObject["RM"].toInt(); if (addrIn != macro_addr) { errMsg = "收包Macro地址錯誤"; return false; } //RET if (jsonObject.contains("RET")) { QJsonValue jsonValueList = jsonObject.value("RET"); QJsonObject item = jsonValueList.toObject(); //ERR int errCode = item["ERR"].toInt(); if (errCode != 0) { //MSG QString err = item["MSG"].toString(); errMsg = QString("CNC反饋錯誤,錯誤碼:%1,詳情:%2").arg(errCode).arg(err); return false; } } //DATA if (jsonObject.contains("DATA")) { QJsonValue jsonValueList = jsonObject.value("DATA"); QJsonObject item = jsonValueList.toObject(); macro_value = item["RMV"].toDouble(); }
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() ConfigFile.h

#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; } ConfigFile.cpp
此類采用單例模式,可供多線程是使用,同時,添加了個人認為很又必要的一些內容。
轉自:https://www.cnblogs.com/kyzc/p/13964243.html