Qt基础之配置文件
在项目开发中,配置文件通常分为三种: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; }
此类采用单例模式,可供多线程是使用,同时,添加了个人认为很又必要的一些内容。