在项目开发中,配置文件通常分为三种: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必须包含头文件:和
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 //代码效果参考:http://www.jhylw.com.cn/163423697.html
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;
}
View Code
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;
}
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结构:
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 <