在项目开发中,配置文件通常分为三种: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;
View Code
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;
View Code
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 }
View Code
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 }
View Code
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();
View Code
以下代码展示解析简单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 }
View Code
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
此类采用单例模式,可供多线程是使用,同时,添加了个人认为很又必要的一些内容。