第十三章 文件的读写操作
Qt提供两种读写纯文本文件的方法:
1、直接使用 QFile 类的IO功能;
2、结合 QFile 和 QTextStream,利用流(Stream)进行操作。
13.1 文件读操作
13.1.1 使用QFile类
Qt封装了QFile类,方便我们对文件进行操作,可以按照如下的步骤进行:
- 使用QFile加载文件对象
- 打开文件 file.open(打开方式)
- 操作文件
- 关闭文件 file.close()
实例:点击读写文件按钮,读取文件内容到 textEdit中
设置ui界面
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
MyDialog md;
// 点击选取文件按钮,弹出文件对话框
md.connect(md.ui->pushButton,&QPushButton::clicked,[&]() {
QString path= QFileDialog::getOpenFileName(md.ui->pushButton, //对话框部件
"打开文件", //对话框标题
"C:/Users/WFD/Desktop"); //默认打开路径,找不到就是工作目录
// 将路径显示在lineEdit中
md.ui->textEdit_2->setText(path);
// 读取文件内容,放入textEdit中
QFile file(path);//参数就是文件的路径
// 设置打开方式
file.open(QIODevice::ReadOnly);
// 用QByteArray类去接收读取的信息
QByteArray array=file.readAll();
// 将读取到的数据放入textEdit中
md.ui->textEdit->setText(array);
// 关闭文件对象
file.close();
});
md.show();
// 进入Qt应用程序的事件循环
return app.exec();
}
QFile::open() 函数打开文件时需要传递 `QIODevice::OpenModeFlag` 枚举类型的参数,决定文件以什么方式打开。
QIODevice::ReadOnly //以只读方式打开文件,用于载入文件。
QIODevice::WriteOnly //以只写方式打开文件,用于保存文件。
QIODevice::ReadWrite //以读写方式打开。
QIODevice::Append //以添加模式打开,新写入文件的数据添加到文件尾部。
QIODevice::Truncate //以截取方式打开文件,文件原有的内容全部被删除。
QIODevice::Text //以文本方式打开文件,读取时“\n”被自动翻译为换行符,
//写入时字符串结束符会自动翻译为系统平台的编码,
//如 Windows 平台下是“\r\n”。
//这些取值可以组合,例如 QIODevice::ReadOnly | QIODevice::Text 表示以只读和文本方式打开文件。
操作文件时,若以只读方式打开文本文件,可用QFile::readAll()一次读取全部内容,
返回QByteArray,需转为QString查看。或使用readLine()逐行读取,并用file.atEnd()判断是否结束:
QByteArray array;
while (!file.atEnd()) {
array += file.readLine();
}
13.1.2 使用QTextStream类
如果操作的是文本文件,Qt还专门封装了一个处理文本流的QTextStream类,我们可以用它来读取文本内容。
// 点击选取文件按钮,弹出文件对话框
connect(ui->pushButton,&QPushButton::clicked,[=]() {
QString path = QFileDialog::getOpenFileName(this,"打开文件","C:/Users/WFD/Desktop");
// 将路径放在lineEdit中
ui->lineEdit->setText(path);
// 读取文件内容,放入textEdit中
QFile file(path); // 参数就是文件的路径
// 设置打开方式
file.open(QIODevice::ReadOnly);
// 用QTextStream类去读取文本信息
QTextStream QS(&file);
// 用QString类去接收读取的信息
QString array = QS.readAll();
// 将读取到的数据放入textEdit中
ui->textEdit->setText(array);
// 关闭文件对象
file.close();
}
13.2 文件写操作
13.2.1 使用QFile类
使用QFile同样可以对文件进行写操作:
//获取要写入的文件路径
QString path = QFileDialog::getSaveFileName(
this, // 父窗口
"保存", // 对话框标题
"D:\\temp\\",// 默认目录
"TXT (*.txt)"// 文件过滤器
);
QFile file(path);
if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
file.write("你好"); //写入
file.close();
} else {
// 处理文件打开失败的情况
qDebug() << "无法打开文件以写入";
}
13.2.2 使用QTextStream类
QTextStream类对操作符进行了重载,我们可以通过 << 操作符将字符串流入文本文件:
QString path = QFileDialog::getSaveFileName(this, //父指针
"保存",//对话窗口名称
"D:\\temp\\",//要保存的路径
"TXT(*.txt)");//文件过滤器
QFile file(path);
file.open(QIODevice::WriteOnly | QIODevice::Text);
QTextStream out(&file);
QString str = "你好";
out << str;
file.close();
13.3 文件信息读取
Qt提供了QFileInfo类,用于获取文件的元数据,包括文件大小、后缀名、创建及最后修改时间等。
QString path = QFileDialog::getOpenFileName(this, //父窗口
"打开文件", //窗口名
"D:\\temp\\"); //路径
QFileInfo file(path);
qDebug() << "文件名" << file.fileName();
qDebug() << "后缀名" << file.suffix();
qDebug() << "文件大小" << file.size();
qDebug() << "创建日期" << file.birthTime().toString("yyyy/MM/dd hh:mm:ss");
qDebug() << "最后修改" << file.lastModified().toString("yyyy/MM/dd hh:mm:ss");
编码转换
QString 转 QByteArray: 使用 QString.toUtf8()。
QString qstr = "example";
QByteArray byteArray = qstr.toUtf8();
QByteArray 转 std::string: 使用 QByteArray.toStdString()。
QByteArray byteArray = ...;
std::string stdStr = byteArray.toStdString();
std::string 转 char *: 使用 std::string.c_str()(注意:返回的是指向内部数据的常量指针,需确保std::string在指针使用期间不被修改或销毁)。
std::string stdStr = "example";
const char* cStr = stdStr.c_str();
// 若需要非const char*,可考虑复制一份数据:
char* writableCStr = new char[stdStr.size() + 1];
std::strcpy(writableCStr, stdStr.c_str());
// 使用后需删除:
delete[] writableCStr;
常用静态函数
QFileDialog::getOpenFileName(): 弹出文件选择对话框,返回用户选择的文件路径。
QString filePath = QFileDialog::getOpenFileName(this, "打开文件", "D:\\temp\\");
QFileDialog::getExistingDirectory(): 弹出目录选择对话框,返回用户选择的目录路径。
QString dirPath = QFileDialog::getExistingDirectory(this, "选择目录", "D:\\temp\\");
QFileDialog::getSaveFileName(): 弹出文件保存对话框,返回用户指定的保存文件路径。
QString savePath = QFileDialog::getSaveFileName(this, //父窗口
"保存文件", //窗口名称
"D:\\temp\\", //打开的目录i
"TXT (*.txt)"); //文件过滤,只显示.txt后缀
13.4 QT配置ini文件
13.4.1 ini文件介绍
.ini 文件是初始化文件,用于配置应用软件以满足用户需求。
它广泛存在于多个操作系统中,并可通过应用程序的图形界面进行操作,而无需直接编辑文件。.ini 文件可存储软件信息和注册表信息等。
13.4.2 ini文件格式
ini 文件由节、键和值构成。
节用方括号 [ ] 包围,如 [Section1 Name],用于区分不同用途的参数区。
键和值通过等号 = 连接,如 KeyName1=value1。
注解使用分号 ;,其后内容至行尾均为注解。
[Section1 Name]
KeyName1=value1
KeyName2=value2
; 这是注解
[Section2 Name]
KeyName21=value21
KeyName22=value22
13.4.3 Qt写ini文件
在 Qt 中,可以使用 QSettings 类来读写 .ini 文件。
#include <QApplication>
#include <QSettings>
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
// 创建 QSettings 对象,指定 ini 文件路径和格式
QSettings *settings = new QSettings(
"hahaya.ini", // .ini 文件名
QSettings::IniFormat // 指定文件格式为 INI
);
// 写入键值对到 ini 文件
settings->setValue("/ip/first", "192.168.0.1");
settings->setValue("ip/second", "127.0.0.1");
settings->setValue("port/open", "2222");
// 删除 QSettings 对象
delete settings;
return a.exec();
}
13.4.4 Qt读ini文件
在 Qt 框架中,我们利用 QSettings 类来读取 .ini 配置文件。
#include <QApplication>
#include <QSettings>
#include <QDebug>
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
// 创建 QSettings 对象以读取 ini 文件
QSettings *settings = new QSettings("hahaya.ini", QSettings::IniFormat);
// 从 ini 文件中读取数据并转换为 QString
QString ipResult = settings->value("/ip/second").toString();
QString portResult = settings->value("/port/open").toString();
// 输出读取的数据
qDebug() << ipResult;
qDebug() << portResult;
// 读取完成后删除 QSettings 对象
delete settings;
return a.exec();
}
13.5 Qt对 Json 文件读写
13.5.1 Json文件介绍
JSON(JavaScript Object Notation)是一种轻量级、语言无关的数据交换格式,用于存储和表示数据。它具有简洁清晰的层次结构,易于阅读和编写,同时也方便机器解析和生成,提高了网络传输效率。
JSON主要处理两方面任务:数据序列化用于网络传输,以及写磁盘文件实现数据持久化存储(文件后缀通常为.json)。
JSON包含两种基本数据格式:JSON数组和JSON对象。
JSON数组:使用[ ]表示,内部元素用逗号分隔,支持多种数据类型混合,包括整形、浮点、字符串、布尔类型、JSON数组、JSON对象和空值null。
// 整形数组
[1, 2, 3, 4, 5]
// 混合类型数组
[12, 13.34, true, false, "hello, world", null]
// 数组嵌套
[
["cat", "dog", "panda"],
["北京", "上海", "天津"],
["luffy", "boy", 19]
]
// 数组和对象嵌套
[
{
"luffy": {
"age": 19,
"father": "Monkey·D·Dragon"
}
}
]
JSON对象:使用{}表示,内部键值对用逗号分隔,键必须是字符串且唯一,值可以是多种数据类型。
{
"Name": "Ace",
"Sex": "man",
"Age": 20,
"Family": {
"Father": "Gol·D·Roger",
"Mother": "Portgas·D·Rouge",
"Brother": ["Sabo", "Monkey D. Luffy"]
},
"IsAlive": false,
"Comment": "yyds"
}
一个JSON文件只能有一个根节点(JSON对象或JSON数组),不允许有多个并列根节点。
/*正确示例,单个根节点*/
{
"userInfo": {
"name": "luffy",
"age": 19
},
"account": {
"user": "ace",
"passwd": "123456"
}
}
13.5.2 Json在Qt中的使用
从Qt 5.0起,Qt支持JSON,提供了四个主要类用于数据组织和解析。
Json类 | 介绍 |
---|---|
QJsonDocument | 封装JSON文档,支持UTF-8和Qt二进制格式的读写。 |
QJsonArray | 值列表,可插入和删除 |
QJsonObject | 键值对列表,键为唯一字符串,值为QJsonValue |
QJsonValue | 封装JSON数据类型。 |
13.5.3 QJsonValue
在Qt中,QJsonValue可封装六种基础数据类型:布尔、浮点(含整形)、字符串、JSON数组、JSON对象和空值。
QJsonValue jsonBool(true); // 布尔类型
QJsonValue jsonDouble(3.14); // 浮点类型
QJsonValue jsonString("Hello"); // 字符串类型
// ... 其他类型的构造类似
要判断QJsonValue内部封装的数据类型,可使用相应的判断函数:
bool isArray() const; // 判断是否为JSON数组
bool isObject() const; // 判断是否为JSON对象
// ... 其他判断函数类似
在确定数据类型后,可将其转换为对应的基础数据类型:
QJsonArray toArray() const; // 转换为JSON数组
bool toBool() const; // 转换为布尔类型
double toDouble() const; // 转换为浮点类型
// ... 其他转换函数类似
QString toString() const; // 转换为字符串类型
13.5.4 QJsonObject
QJsonObject用于封装JSON对象,可存储多个键值对,其中键为字符串,值为QJsonValue。
以下是一些常用API函数的精简介绍及示例代码:
// 创建空的QJsonObject对象
QJsonObject jsonObject;
// 添加键值对到QJsonObject中
jsonObject.insert("key1", QJsonValue(123)); // 添加整型值,键为"key1"
jsonObject.insert("key2", QJsonValue("value2")); // 添加字符串值,键为"key2"
// 获取QJsonObject中键值对的个数
int count = jsonObject.size(); // 使用size()函数获取个数,count()和length()也是等效的
// 通过键获取QJsonObject中的值
QJsonValue value1 = jsonObject.value("key1"); // 使用value()函数,根据键"key1"获取值
QJsonValue value2 = jsonObject["key2"]; // 使用operator[],根据键"key2"获取值
// 删除QJsonObject中的键值对
jsonObject.remove("key1"); // 删除键"key1"对应的键值对
QJsonValue takenValue = jsonObject.take("key2"); // 删除并返回键"key2"对应的值
// 通过键在QJsonObject中查找
auto it = jsonObject.find("key3"); // 查找键"key3",返回迭代器
bool containsKey = jsonObject.contains("key4"); // 判断是否包含键"key4"
遍历键值对,
1、使用迭代器
// 遍历QJsonObject中的键值对
// 方法1:使用迭代器遍历
for (auto it = jsonObject.begin(); it != jsonObject.end(); ++it) {
QString key = it.key();
QJsonValue value = it.value();
// 在此处处理每个键值对
}
2、使用[ ]方式(不推荐,因为需要知道所有键):
// 方法2:先获取所有键,然后遍历键列表(推荐)
QStringList keys = jsonObject.keys(); // 获取QJsonObject中所有键的列表
for (const QString &key : keys) {
QJsonValue value = jsonObject.value(key); // 根据键获取值
// 在此处处理每个键值对
}
// 注意:方法2中也可以使用operator[]来获取值,但推荐使用value()函数,
// 因为如果键不存在,operator[]可能会插入一个空值,而value()则不会。
13.5.5 QJsonArray
QJsonArray用于封装JSON数组,可存储多个QJsonValue类型的元素。
//创建空数组
QJsonArray jsonArray;
//添加数据
jsonArray.append(QJsonValue(123)); // 在尾部追加整型值
jsonArray.insert(1, QJsonValue("inserted")); // 在索引1之前插入字符串值
jsonArray.prepend(QJsonValue(true)); // 在数组头部添加布尔值
// push_back和push_front与append和prepend功能相同,但命名遵循STL风格
jsonArray.push_back(QJsonValue(456));
jsonArray.push_front(QJsonValue(false));
//计算数组元素个数
int count = jsonArray.size(); // 使用size()函数,count()也是等效的
//从数组中取出元素
QJsonValue valueAt0 = jsonArray.at(0); // 取出索引0的元素
QJsonValue firstValue = jsonArray.first(); // 取出头部元素
QJsonValue lastValue = jsonArray.last(); // 取出尾部元素
QJsonValue valueAtIndex = jsonArray[2]; // 使用operator[]取出索引2的元素
//删除数组中的元素
auto it = jsonArray.begin(); // 获取迭代器
it++; // 移动迭代器到第二个元素
jsonArray.erase(it); // 删除迭代器指向的元素
jsonArray.pop_back(); // 删除尾部元素
jsonArray.pop_front(); // 删除头部元素
jsonArray.removeAt(1); // 删除索引1的元素
jsonArray.removeFirst(); // 删除头部元素
jsonArray.removeLast(); // 删除尾部元素
QJsonValue takenValue = jsonArray.takeAt(0); // 删除索引0的元素并返回其值
QJ遍历数组:
使用迭代器遍历:
for (auto it = jsonArray.begin(); it != jsonArray.end(); ++it) {
QJsonValue value = *it;
// 处理每个元素
}
使用数组方式遍历:
for (int i = 0; i < jsonArray.size(); ++i) {
QJsonValue value = jsonArray.at(i);
// 处理每个元素
}
13.5.6 QJsonDocument
在Qt中,QJsonDocument类用于封装完整的JSON文档,并支持从UTF-8编码的文本表示以及Qt的二进制格式读取和写入该文档。
QJsonObject 或 QJsonArray 转换为字符串
1、创建QJsonDocument对象:
用QJsonDocument构造函数,将QJsonObject或QJsonArray转换为QJsonDocument对象。
QJsonObject jsonObject;
// ... 填充jsonObject数据
QJsonDocument jsonDoc(jsonObject);
QJsonArray jsonArray;
// ... 填充jsonArray数据
QJsonDocument jsonDocArray(jsonArray);
2、序列化数据:
调用toBinaryData()或toJson()方法,将QJsonDocument对象序列化为二进制格式或文本格式的JSON字符串。
QByteArray binaryData = jsonDoc.toBinaryData();
QByteArray jsonString = jsonDoc.toJson(QJsonDocument::Indented); // 文本格式,带缩进
3、使用字符串进行数据传输或持久化:
将得到的字符串通过网络传输或保存到磁盘文件中。
字符串 转换为 QJsonObject 或 QJsonArray
1、解析字符串为QJsonDocument对象:
使用QJsonDocument的静态函数fromBinaryData()或fromJson(),将JSON字符串解析为QJsonDocument对象
QByteArray jsonString = ... // 从网络或文件获取的JSON字符串
QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonString);
2、将文档对象转换为QJsonArray或QJsonObject:
使用isArray()或isObject()方法判断QJsonDocument对象中的数据类型,然后调用array()或object()方法将其转换为相应的对象。
if (jsonDoc.isObject()) {
QJsonObject jsonObject = jsonDoc.object();
// ... 处理jsonObject
} else if (jsonDoc.isArray()) {
QJsonArray jsonArray = jsonDoc.array();
// ... 处理jsonArray
}
3、读取数据:
使用QJsonArray或QJsonObject提供的API读取存储在对象中的数据。