最近做了一个基于Qt的对于.xml文件和.ini文件的写入和读取项目(Qt版本为5.12.10).在输入框中输入数据,点击确认按钮,选择是否修改配置文件,然后选择对应的文件类型(xml或者ini文件),即可将数据写入配置文件。Qt 的UI界面如下所示:
下面是项目的源代码展示,包含四个内容:
QT += core gui
QT += xml
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
CONFIG += c++11
# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
main.cpp \
readandwritefile.cpp
HEADERS += \
readandwritefile.h
FORMS += \
readandwritefile.ui
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
#ifndef READANDWRITEFILE_H
#define READANDWRITEFILE_H
/********************************************
* @headerfile: readandwritefile.h
* @brief: 声明了ReadandWriteFile类,该类用于读取和写入文件。
* 包含了一些与文件处理相关的方法和槽函数。
* @author: Jacky Zou
* @date: 2023-07-31
*********************************************/
#include
#include
#include
namespace Ui {
class ReadandWriteFile;
} // namespace Ui
class ReadandWriteFile : public QMainWindow
{
Q_OBJECT
public:
/**
* @brief ReadandWriteFile类的构造函数。
* @param parent 父级窗口的指针,默认为nullptr。
*/
explicit ReadandWriteFile(QWidget *parent = nullptr);
~ReadandWriteFile(); // ReadandWriteFile类的析构函数。
public:
void writeXml(); // 写入xml数据到xml文件
void readXml(); // 读取xml文件
bool openXml(QString &fileNamePath_); // 打开xml文件
void readRootXml(QDomNodeList &sonNodeLists_); // 处理子节点集
static void iniDataWrite(const QString& filename, Ui::ReadandWriteFile *ui); // 静态方法写入ini文件
static void iniDataRead(const QString& filename); // 静态方法读取ini文件
private slots:
void on_readBtn_clicked(); // 读取按钮的槽函数
void on_cancelBtn_clicked(); // 取消按钮的槽函数
void on_writeBtn_clicked(); // 确认(写入)按钮的槽函数
private:
Ui::ReadandWriteFile *ui;
QFile xml_file; // 创建对象
QString currentXmlFilePath_; // 当前xml文件路径
QString currentIniFilePath_; // 当前Ini文件路径
QString currentXmlFileName_; // 当前xml文件名
QString currentIniFileName_; // 当前ini文件名
QVector<QString> inputData_; // 用户输入的数据
};
#endif // READANDWRITEFILE_H
#include "readandwritefile.h"
#include "ui_readandwritefile.h"
#include
#include
#include
#include
#include
#include
/**********************************************
* @projectName ReadandWriteFile
* @brief ReadandWriteFile类的构造函数。
* @param parent 父级窗口的指针,默认为nullptr。
* @details 构造函数用于初始化ReadandWriteFile对象,并设置界面的初始状态。
* 在构造函数中,设置了输入框的验证器,以限制输入数据库IP和端口号的格式。
* 还初始化了当前xml文件路径、当前ini文件路径以及xml和ini配置文件的名称。
* @author Jacky Zou
* @date 2023-07-31
**********************************************/
ReadandWriteFile::ReadandWriteFile(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::ReadandWriteFile)
{
ui->setupUi(this);
// 使用IPv4地址的正则表达式来限制输入数据库IP
QString dbIP = "\\b((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\b";
ui->lineEdit->setValidator(new QRegExpValidator(QRegExp(dbIP)));
ui->lineEdit->setInputMask("000.000.000.000");
// 使用正则表达式限制输入数据库端口号
QString portNum = "^([0-9]|[1-9]\\d|[1-9]\\d{2}|[1-9]\\d{3}|[1-5]\\d{4}|6[0-4]\\d{3}|65[0-4]\\d{2}|655[0-2]\\d|6553[0-5])$";
ui->lineEdit_5->setValidator(new QRegExpValidator(QRegExp(portNum)));
currentXmlFilePath_ = QCoreApplication::applicationDirPath(); // 当前xml文件路径
currentIniFilePath_ = QCoreApplication::applicationDirPath(); // 当前Ini文件路径
currentXmlFileName_ = "/database.xml"; // xml配置文件名称
currentIniFileName_ = "/database.ini"; // ini配置文件名称
}
// ReadandWriteFile类的析构函数。
ReadandWriteFile::~ReadandWriteFile()
{
delete ui;
}
/**********************************************
* @projectName ReadandWriteFile
* @brief 写入xml文件
* @param void
* @return void
* @author Jacky Zou
* @date 2023-07-31
**********************************************/
void ReadandWriteFile::writeXml()
{
// 判断文件是否存在
if (QFile::exists(currentXmlFilePath_ + currentXmlFileName_)) {
QFile::remove(currentXmlFilePath_ + currentXmlFileName_); // 删除文件
}
// 文件存在则创建,否则创建一个文件
if(!openXml(currentXmlFileName_)) {
qDebug() << qPrintable("写入时,打开文件失败");
return;
}
QDomDocument domDoc; // 创建xml类
QDomProcessingInstruction version; // 创建xml处理类,通常用于处理第一行描述信息
version = domDoc.createProcessingInstruction("xml","version=\"1.0\" encoding=\"UTF-8\""); // 创建xml头部格式
domDoc.appendChild(version); // 添加到xml文件
QDomElement domRootElement = domDoc.createElement("XMLConfigFile"); // 创建xml文件根节点
domDoc.appendChild(domRootElement);
QDomElement fatherNodeElement = domDoc.createElement("admin"); // 创建父节点
domRootElement.appendChild(fatherNodeElement); // 添加关系,将父节点挂到根节点
QDomElement sonNode1 = domDoc.createElement("DBIP"); // 创建子节点
QDomText sonText1 = domDoc.createTextNode("数据库IP:" + ui->lineEdit->text()); // 设置尖括号中的值
// 添加关系,将子节点挂至父节点
sonNode1.appendChild(sonText1);
fatherNodeElement.appendChild(sonNode1);
QDomElement sonNode2 = domDoc.createElement("PortNumber"); // 创建子节点
QDomText sonText2 = domDoc.createTextNode("数据库端口号:" + ui->lineEdit_5->text()); // 设置尖括号中的值
// 添加关系,将子节点挂至父节点
sonNode2.appendChild(sonText2);
fatherNodeElement.appendChild(sonNode2);
QDomElement sonNode3 = domDoc.createElement("DriverName"); // 创建子节点
QDomText sonText3 = domDoc.createTextNode("驱动名称:" + ui->lineEdit_2->text()); // 设置尖括号中的值
// 添加关系,将子节点挂至父节点
sonNode3.appendChild(sonText3);
fatherNodeElement.appendChild(sonNode3);
QDomElement sonNode4 = domDoc.createElement("DBName"); // 创建子节点
QDomText sonText4 = domDoc.createTextNode("数据库名:" + ui->lineEdit_6->text()); // 设置尖括号中的值
// 添加关系,将子节点挂至父节点
sonNode4.appendChild(sonText4);
fatherNodeElement.appendChild(sonNode4);
QDomElement sonNode5 = domDoc.createElement("UserName"); // 创建子节点
QDomText sonText5 = domDoc.createTextNode("用户名:" + ui->lineEdit_3->text()); // 设置尖括号中的值
// 添加关系,将子节点挂至父节点
sonNode5.appendChild(sonText5);
fatherNodeElement.appendChild(sonNode5);
QDomElement sonNode6 = domDoc.createElement("Password"); // 创建子节点
QDomText sonText6 = domDoc.createTextNode("密码:" + ui->lineEdit_4->text()); // 设置尖括号中的值
// 添加关系,将子节点挂至父节点
sonNode6.appendChild(sonText6);
fatherNodeElement.appendChild(sonNode6);
// 将其写入到xml文件中
QTextStream stream(&xml_file);
domDoc.save(stream, 4); // 缩进四格
xml_file.close();
}
/**********************************************
* @projectName ReadandWriteFile
* @brief 读取xml文件
* @param void
* @return void
* @author Jacky Zou
* @date 2023-07-31
**********************************************/
void ReadandWriteFile::readXml()
{
// 打开或创建文件
if(!openXml(currentXmlFileName_)) {
qDebug() << qPrintable("读取时,打开文件失败");
return;
}
QDomDocument doc;
// 设置变量定位xml文件中出错的地方
int errLine = -1;
int errColum = -1;
QString strError = "";
if(!doc.setContent(&xml_file, true, &strError, &errLine, &errColum)) {
qDebug() << strError << "line: " << errLine << "colum: " << errColum; // 打印报错位置
xml_file.close();
qDebug() << qPrintable("读取xml文件失败");
return;
}
xml_file.close(); // 关闭之前打开的文件,释放文件资源,并确保文件的写入操作已完成。
QDomElement root = doc.documentElement(); // 返回根节点
QDomNode node = root.firstChild(); // 获得第一个子节点
while (!node.isNull()) { // 遍历节点
QDomNodeList nodelists = node.childNodes(); // 获取当前节点的子节点列表
QString root = node.toElement().tagName(); // 获取当前节点的标签名
if(root == "admin") {
readRootXml(nodelists); // 调用readRootXml节点匹配函数,读取并打印输出
}
node = node.nextSibling(); // 读取下一个兄弟节点
}
}
/**********************************************
* @projectName ReadandWriteFile
* @brief 读取每个节点,判断每个节点的标签名,
* 若标签名匹配,则打印该节点的文本内容
* @param sonNodeLists_ 子节点列表
* @return void
* @author Jacky Zou
* @date 2023-07-31
**********************************************/
void ReadandWriteFile::readRootXml(QDomNodeList &sonNodeLists_)
{
for (int i = 0; i < sonNodeLists_.size(); i++) {
QDomElement sonElement = sonNodeLists_.at(i).toElement();
if(sonElement.toElement().tagName().compare("DBIP") == 0) {
qDebug() << qPrintable(sonElement.text()); // qPrintable()用于去除打印结果的双引号
} else if (sonElement.toElement().tagName().compare("PortNumber") == 0) {
qDebug() << qPrintable(sonElement.text());
} else if (sonElement.toElement().tagName().compare("DriverName") == 0) {
qDebug() << qPrintable(sonElement.text());
} else if (sonElement.toElement().tagName().compare("DBName") == 0) {
qDebug() << qPrintable(sonElement.text());
} else if (sonElement.toElement().tagName().compare("UserName") == 0) {
qDebug() << qPrintable(sonElement.text());
} else if (sonElement.toElement().tagName().compare("Password") == 0) {
qDebug() << qPrintable(sonElement.text());
}
}
}
// 打开xml文件,并返回打开操作的结果(成功或失败)
bool ReadandWriteFile::openXml(QString &fileNamePath_)
{
xml_file.setFileName(currentXmlFilePath_ + "./" + fileNamePath_);
return xml_file.open(QIODevice::ReadWrite | QFile::Text); // 调用xml_file的open函数以读写模式打开文件
}
/**********************************************
* @projectName ReadandWriteFile
* @brief 将数据写入ini文件
* @param filename 文件名
* @param ui UI对象指针
* @return void
* @author Jacky Zou
* @date 2023-07-31
**********************************************/
void ReadandWriteFile::iniDataWrite(const QString& filename, Ui::ReadandWriteFile *ui)
{
QString filePath = QCoreApplication::applicationDirPath()+ "./" + filename; // 写入路径
QSettings settings(filePath, QSettings::IniFormat); // 使用`QSettings`直接打开ini文件,并将数据写入其中
// 设置ini文件的编码为UTF-8
QTextCodec *codec = QTextCodec::codecForName("UTF-8");
settings.setIniCodec(codec);
// 写入配置信息
QString value1 = QString("数据库IP:") + ui->lineEdit->text(); // 获取数据库IP编辑框的文本
QString value2 = QString("驱动名称:") + ui->lineEdit_2->text(); // 获取驱动名称编辑框的文本
QString value3 = QString("用户名:") + ui->lineEdit_3->text(); // 获取用户名编辑框的文本
QString value4 = QString("密码:") + ui->lineEdit_4->text(); // 获取密码编辑框的文本
QString value5 = QString("数据库端口号:") + ui->lineEdit_5->text(); // 获取数据库端口号编辑框的文本
QString value6 = QString("数据库名:") + ui->lineEdit_6->text(); // 获取数据库名编辑框的文本
// 将键(key)和值(value)写入ini文件的节(section)中
settings.setValue(QString("Section1/Key1"), value1);
settings.setValue(QString("Section2/Key2"), value2);
settings.setValue(QString("Section3/Key3"), value3);
settings.setValue(QString("Section4/Key4"), value4);
settings.setValue(QString("Section5/Key5"), value5);
settings.setValue(QString("Section6/Key6"), value6);
// 写入ini文件后检查是否发生了错误,并打印错误信息
if (settings.status() != QSettings::NoError) {
qDebug() << qPrintable("写入文件时发生错误:") << settings.status();
}
settings.sync(); // 将内存中的设置同步到硬盘上的配置文件中
}
/**********************************************
* @projectName ReadandWriteFile
* @brief 从ini文件中读取数据
* @param filename 文件名
* @return void
* @author Jacky Zou
* @date 2023-07-31
**********************************************/
void ReadandWriteFile::iniDataRead(const QString& filename)
{
QString filePath = QCoreApplication::applicationDirPath()+ "./" + filename; // 读取路径
QSettings settings(filePath, QSettings::IniFormat); // 使用`QSettings`直接打开ini文件,并读取其中的数据
// 设置ini文件的编码为UTF-8
QTextCodec *codec = QTextCodec::codecForName("UTF-8");
settings.setIniCodec(codec);
// 读取配置信息
// 从ini文件的节(section)中读取键(key)的值
QString value1 = settings.value("Section1/Key1").toString();
QString value2 = settings.value("Section2/Key2").toString();
QString value3 = settings.value("Section3/Key3").toString();
QString value4 = settings.value("Section4/Key4").toString();
QString value5 = settings.value("Section5/Key5").toString();
QString value6 = settings.value("Section6/Key6").toString();
// 在qDebug()中显示读取的配置信息
qDebug() << qPrintable(value1);
qDebug() << qPrintable(value2);
qDebug() << qPrintable(value3);
qDebug() << qPrintable(value4);
qDebug() << qPrintable(value5);
qDebug() << qPrintable(value6);
// 读取ini文件后检查是否发生了错误,并打印错误信息
if (settings.status() != QSettings::NoError) {
qDebug() << qPrintable("读取文件时发生错误:") << settings.status();
}
}
// 读取按钮的槽函数
void ReadandWriteFile::on_readBtn_clicked()
{
// 将QMessageBox的 “Yes” 按钮 改为 “是”, “No” 改为 “否”
QMessageBox confirm(QMessageBox::Question, tr("将要读取配置文件"), tr("是否确认读取?"), QMessageBox::Yes | QMessageBox::No);
confirm.setButtonText(QMessageBox::Yes, tr("是"));
confirm.setButtonText(QMessageBox::No, tr("否"));
int choose = confirm.exec();
// 如果选择“是”,则进行下一步
if(choose == QMessageBox::Yes) {
QMessageBox whichFileType(QMessageBox::Question, tr("选择文件类型"), tr("选择要读取哪种文件?"), QMessageBox::Yes | QMessageBox::No);
whichFileType.setButtonText(QMessageBox::Yes, tr("xml"));
whichFileType.setButtonText(QMessageBox::No, tr("ini"));
int fileType = whichFileType.exec();
// 如果确认读取配置文件,接下来选择要读取哪种文件,xml或ini
if(fileType == QMessageBox::Yes) {
qDebug() << qPrintable("读取xml文件成功");
qDebug() << qPrintable("当前读取文件路径:") << currentXmlFilePath_ + currentXmlFileName_;
qDebug() << qPrintable("读取文件内容如下:");
readXml(); // 调用xml读取函数
} else if(fileType == QMessageBox::No) {
qDebug() << qPrintable("读取ini文件成功");
qDebug() << qPrintable("当前读取文件路径:") << currentIniFilePath_ + currentIniFileName_;
qDebug() << qPrintable("读取文件内容如下:");
iniDataRead(currentIniFileName_); // 调用ini读取函数
}
return;
}
}
// 取消按钮的槽函数
void ReadandWriteFile::on_cancelBtn_clicked()
{
this->close(); // 关闭当前窗口
}
// 确认(写入)按钮的槽函数
void ReadandWriteFile::on_writeBtn_clicked()
{
// 将QMessageBox的 “Yes” 按钮 改为 “是”, “No” 改为 “否”
QMessageBox confirm(QMessageBox::Question, tr("将要修改配置文件"), tr("是否确认修改?"), QMessageBox::Yes | QMessageBox::No);
confirm.setButtonText(QMessageBox::Yes, tr("是"));
confirm.setButtonText(QMessageBox::No, tr("否"));
int choose = confirm.exec();
// 如果选择“是”,则进行下一步
if(choose == QMessageBox::Yes) {
QMessageBox whichFileType(QMessageBox::Question, tr("选择文件类型"), tr("选择要修改哪种文件?"), QMessageBox::Yes | QMessageBox::No);
whichFileType.setButtonText(QMessageBox::Yes, tr("xml"));
whichFileType.setButtonText(QMessageBox::No, tr("ini"));
int fileType = whichFileType.exec();
// 如果确认修改配置文件,接下来选择要修改哪种文件,xml或ini
if(fileType == QMessageBox::Yes) {
writeXml(); // 调用xml写入函数
qDebug() << qPrintable("写入xml文件成功");
qDebug() << qPrintable("当前写入文件路径:") << currentXmlFilePath_ + currentXmlFileName_;
} else if(fileType == QMessageBox::No) {
iniDataWrite(currentIniFileName_, ui); // 调用ini写入函数
qDebug() << qPrintable("写入ini文件成功");
qDebug() << qPrintable("当前写入文件路径:") << currentIniFilePath_ + currentIniFileName_;
}
return;
}
}
#include "readandwritefile.h"
#include
#include
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
ReadandWriteFile w;
w.show();
//设置中文编码,防止编码格式的问题导致乱码
#if (QT_VERSION <= QT_VERSION_CHECK(5,0,0))
#if _MSC_VER
// 使用GBK编码
QTextCodec *codec = QTextCodec::codecForName("GBK");
#else
QTextCodec *codec = QTextCodec::codecForName("UTF-8");
#endif
// 将选定的编码方式设置为当前的本地编码、C字符串编码和翻译字符串编码
QTextCodec::setCodecForLocale(codec);
QTextCodec::setCodecForCStrings(codec);
QTextCodec::setCodecForTr(codec);
#else
// 使用UTF-8编码
QTextCodec *codec = QTextCodec::codecForName("UTF-8");
// 将选定的编码方式设置为当前的本地编码
QTextCodec::setCodecForLocale(codec);
#endif
return a.exec();
}
这里仅对于.xml文件的写入和读取做了展示,.ini文件的操作完全一样。可自行运行体验。
至此,整个项目代码展示和运行结果展示完毕。建议学习之前首先对于xml文件和ini文件做一个提前了解。然后就是中文编码问题(这个问题困扰了我一段时间,还需进一步学习)也需要好好学一下。
有问题可以联系本人,私信会不定时看。