Qt基础之配置文件(QSettings)
在项目开发中,配置文件通常分为三种: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
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)