前段时间遇到一个小问题,后来发现这是个挺常见的坑,顺手整理一篇笔记。
**
🎬 个人主页:艾莉丝努力练剑
❄专栏传送门:《C语言》《数据结构与算法》《C/C++干货分享&学习过程记录》
《Linux操作系统编程详解》《笔试/面试常见算法:从基础到进阶》《Python干货分享》
⭐️为天地立心,为生民立命,为往圣继绝学,为万世开太平
🎬 艾莉丝的简介:
文章目录
1 ~> QT文件系统概述 2 ~> QFile核心API详解 2.4 写文件2.5 关闭文件close() 3 ~> 实战:简易记事本实现 3.2 打开文件功能实现3.3 保存文件功能实现3.4 运行效果 4 ~> QFileInfo文件信息类 5 ~> 总结 结尾前言 && 全文梗概
导入语
文件操作是所有桌面应用程序不可或缺的核心功能,从简单的文本读写到复杂的配置文件管理、数据持久化都离不开它。Qt作为跨平台开发框架,最大的优势之一就是提供了统一的文件操作API,彻底解决了C/C++原生库和系统API(如Linux的open/read/write、Windows的CreateFile)的平台兼容性问题。Qt诞生于1991年,早于C++标准库的标准化进程,因此其文件系统封装经过了长期的迭代优化,与QString、QByteArray等Qt核心类无缝集成,用起来比C++17才引入的std::filesystem更加便捷高效。
这里将系统讲解Qt文件操作的核心知识,包括I/O设备的继承体系、QFile类的完整API用、从零实现一个支持打开和保存功能的简易记事本、以及QFileInfo类获取文件属性的方法。所有内容均配套完整的可运行代码,适合作为Qt入门学习的复习资料,帮助你快速回忆起文件操作的核心逻辑和常见坑点。
思维导图
1 ~> QT文件系统概述
Qt作为通用跨平台开发库,提供了完善的文件系统操作能力,涵盖文件读写、文件信息获取、文件复制/重命名、目录遍历等所有常见功能。
在Qt出现之前,文件操作主要依赖两种方式:一是C语言标准库的fopen/fclose/fread/fwrite系列函数,二是操作系统原生API。这两种方式都存在明显局限性:C标准库功能有限,无法获取文件的详细属性;系统API则完全不具备跨平台性,Linux下的代码无法直接在Windows上运行。
Qt诞生于1991年,早于C++标准的正式发布(1998年),因此其文件系统封装经过了30多年的迭代优化,不仅完美解决了跨平台问题,还与QString、QByteArray等Qt核心类实现了无缝集成。虽然C++17引入了std::filesystem库,但Qt的文件操作API在易用性、功能完整性和与Qt生态的兼容性上仍然具有明显优势,因此在Qt项目中强烈建议用用Qt自身的文件操作类。
Qt文件操作的核心流程与原生方式完全一致,都遵循"打开→读/写→关闭"的基本逻辑,只是将这些操作封装成了更加易用的类和方法。
1.1 I / O设备继承体系
Qt中所有输入输出设备都继承自QIODevice类,它定义了所有I/O设备的通用接口,如打开、关闭、读、写等。文件、网络套接字、串口、蓝牙、进程通信、内存缓冲区等都属于I/O设备,因此它们都继承自QIODevice。
完整的继承关系如下:
QObject(Qt所有对象的基类)
QIODevice(所有I/O设备的基类)
QFileDevice(文件设备的基类)
QFile(普通文件操作)
QTemporaryFile(临时文件操作)QSaveFile(安全写文件)
QAbstractSocket(网络套接字基类)
QTcpSocket(TCP套接字)QUdpSocket(UDP套接字)
QSerialPort(串口通信)QBluetoothSocket(蓝牙通信)QProcess(进程间通信,封装了fork/exec操作)QBuffer(内存缓冲区操作)
其中QFile是我们最常用的文件操作类,它继承自QFileDevice,提供了普通文件的读写功能。
1.2 QFile相关子类简介
除了QFile之外,Qt还提供了两个非常实用的QFile子类,解决了特定场景下的文件操作问题:
- QTemporaryFile:用于创建临时文件。当
QTemporaryFile对象销毁时,对应的临时文件会自动被删除,非常适合存储临时数据,避免手动清理临时文件的麻烦。 - QSaveFile:用于安全地写入文件。它采用了"先写临时文件,写完再替换原文件"的原子性策略:写入数据时不会直接修改原文件,而是先将内容写入一个临时文件,当所有数据都成功写入后,再删除原文件并将临时文件重命名为原文件名。这种策略可以有效避免写入过程中程序崩溃或断电导致原文件损坏的问题,Java、Redis等众多系统都采用了类似的安全写策略。
2 ~> QFile核心API详解
QFile类是Qt文件操作的核心,它提供了完整的文件打开、读、写、关闭功能,支持绝对路径和相对路径,与Qt的其他类配合非常方便。
2.1 构造函数
QFile的构造函数非常简单,最常用的是:
QFile(const QString &name)
参数name是文件的路径,可以是绝对路径(如C:/test.txt),也可以是相对路径(相对于程序运行的当前目录)。
注意:构造函数只是创建了QFile对象,并不会实际打开文件,必须调用open()方法才能打开文件进行读写操作。
2.2 打开文件open()
打开文件使用open()方法,其原型为:
virtual bool open(QIODevice::OpenMode mode) override
- 返回值:
bool类型,true表示打开成功,false表示打开失败。打开失败的原因可能包括文件不存在、权限不足、路径错误等。 - 参数
mode:文件的打开模式,是QIODevice::OpenMode枚举类型的组合,可以使用按位或|同时指定多个模式。
模式常量数值说明QIODevice::NotOpen0x0000未打开QIODevice::ReadOnly0x0001只读模式,文件必须存在QIODevice::WriteOnly0x0002只写模式,如果文件不存在则创建;如果文件已存在则清空原有内容(除非同时指定Append模式)QIODevice::ReadWrite0x0003读写模式,相当于ReadOnlyQIODevice::Append0x0004追加模式,所有写入操作都在文件末尾进行QIODevice::Truncate0x0008截断模式,打开文件时清空原有内容QIODevice::Text0x0010文本模式,自动转换换行符:在Windows下将\n转换为\r\n,在Linux下保持\n不变QIODevice::Unbuffered0x0020无缓冲模式,绕过系统缓冲区,直接读写磁盘QIODevice::NewOnly0x0040仅新建模式,只有当文件不存在时才创建并打开;如果文件已存在则打开失败QIODevice::ExistingOnly`0x0080仅打开已存在文件模式,如果文件不存在则打开失败
示例:以只读文本模式打开文件
QFile file("test.txt");
bool ret = file.open(QIODevice::ReadOnly | QIODevice::Text);
if (!ret) {
qDebug() 实战:简易记事本实现
下面我们通过一个完整的实战项目,来巩固`QFile`类的使用。我们将实现一个简易的记事本程序,支持打开和保存文本文件。
### 3.1 项目创建与界面搭建
首先创建一个Qt Widgets Application项目,基类选择`QMainWindow`。
#### 3.1.1 mainwindow.h头文件
ifndef MAINWINDOW_H
define MAINWINDOW_H
include
include
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget parent = nullptr);
~MainWindow();
// 处理"打开"菜单项的槽函数
void handleAction1();
// 处理"保存"菜单项的槽函数
void handleAction2();
private:
Ui::MainWindow ui;
// 文本编辑框,作为成员变量方便在槽函数中访问
QPlainTextEdit edit;
};
endif // MAINWINDOW_H
#### 3.1.2 mainwindow.cpp构造函数
在构造函数中完成界面的搭建:
include "mainwindow.h"
include "ui_mainwindow.h"
include
include
include
include
MainWindow::MainWindow(QWidget parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
// 设置窗口标题
this->setWindowTitle("简单的记事本");
// 获取菜单栏
QMenuBar menuBar = this->menuBar();
// 添加"文件"菜单
QMenu menu = new QMenu("文件");
menuBar->addMenu(menu);
// 添加"打开"和"保存"菜单项
QAction action1 = new QAction("打开");
QAction action2 = new QAction("保存");
menu->addAction(action1);
menu->addAction(action2);
// 创建文本编辑框作为中心部件
edit = new QPlainTextEdit();
// 设置字体大小为20像素
QFont font;
font.setPixelSize(20);
edit->setFont(font);
this->setCentralWidget(edit);
// 连接信号槽:菜单项点击触发对应的槽函数
connect(action1, &QAction::triggered, this, &MainWindow::handleAction1);
connect(action2, &QAction::triggered, this, &MainWindow::handleAction2);
}
MainWindow::~MainWindow()
{
delete ui;
}
### 3.2 打开文件功能实现
实现`handleAction1()`槽函数,完成打开文件的功能:
include
include
include
void MainWindow::handleAction1()
{
// 1. 弹出"打开文件"对话框,让用户选择要打开的文件
QString path = QFileDialog::getOpenFileName(this);
// 2. 在状态栏中显示选中的文件路径
QStatusBar statusBar = this->statusBar();
statusBar->showMessage(path);
// 3. 根据用户选择的路径构造QFile对象,并以只读方式打开
QFile file(path);
bool ret = file.open(QIODevice::ReadOnly);
if (!ret) {
// 打开失败,在状态栏显示错误信息
statusBar->showMessage(path + " 打开失败!");
return;
}
// 4. 读取文件的所有内容
QString text = file.readAll();
// 5. 关闭文件
file.close();
// 6. 将读取到的内容显示到文本编辑框中
edit->setPlainText(text);
}
### 3.3 保存文件功能实现
实现`handleAction2()`槽函数,完成保存文件的功能:
void MainWindow::handleAction2()
{
// 1. 弹出"保存文件"对话框,让用户选择保存路径
QString path = QFileDialog::getSaveFileName(this);
// 2. 在状态栏中显示保存路径
QStatusBar statusBar = this->statusBar();
statusBar->showMessage(path);
// 3. 根据用户选择的路径构造QFile对象,并以只写方式打开
QFile file(path);
bool ret = file.open(QIODevice::WriteOnly);
if (!ret) {
// 打开失败,在状态栏显示错误信息
statusBar->showMessage(path + " 打开失败!");
return;
}
// 4. 获取文本编辑框中的内容,并转换为UTF-8编码写入文件
const QString& text = edit->toPlainText();
file.write(text.toUtf8());
// 5. 关闭文件
file.close();
}
### 3.4 运行效果
编译运行程序后,会出现一个带有"文件"菜单的窗口,包含"打开"和"保存"两个菜单项:
- 点击"打开",会弹出文件选择对话框,选择一个文本文件后,文件内容会显示在文本编辑框中,状态栏会显示文件的完整路径。
- 点击"保存",会弹出保存文件对话框,选择保存路径和文件名后,文本编辑框中的内容会被保存到指定的文件中。
---
## 4 ~> QFileInfo文件信息类
`QFileInfo`是Qt提供的用于获取文件和目录属性信息的类,它可以获取文件名、文件大小、文件路径、文件类型、创建时间、修改时间、访问时间等各种属性。在C++17引入`std::filesystem`之前,获取这些属性必须使用操作系统原生API,而`QFileInfo`提供了跨平台的统一接口。
### 4.1 构造函数
`QFileInfo`最常用的构造函数是:
QFileInfo(const QString &file);
QFileInfo(const QFile &file);
参数`file`是文件的路径或`QFile`对象。
### 4.2 常用API
`QFileInfo`提供了非常多的方法来获取文件属性,以下是最常用的一些:
- `QString fileName() const`:返回文件名(包含后缀),如`test.txt`。
- `QString baseName() const`:返回文件的基本名(不包含后缀),如`test`。
- `QString completeBaseName() const`:返回完整的基本名,对于`test.tar.gz`,返回`test.tar`。
- `QString suffix() const`:返回文件的后缀名,对于`test.tar.gz`,返回`gz`。
- `QString completeSuffix() const`:返回完整的后缀名,对于`test.tar.gz`,返回`tar.gz`。
- `QString path() const`:返回文件的路径(不包含文件名)。
- `QString absolutePath() const`:返回文件的绝对路径。
- `qint64 size() const`:返回文件的大小,单位是字节。
- `bool isFile() const`:判断是否为普通文件。
- `bool isDir() const`:判断是否为目录。
- `bool isExecutable() const`:判断是否为可执行文件。
- `bool exists() const`:判断文件是否存在。
- `QDateTime fileTime(QFile::FileTime time) const`:返回文件的时间信息,`time`参数可以是`QFile::FileBirthTime`(创建时间)、`QFile::FileModificationTime`(修改时间)、`QFile::FileAccessTime`(访问时间)。
### 4.3 实战代码
下面通过一个简单的例子演示`QFileInfo`的使用:
#### 4.3.1 widget.h头文件
ifndef WIDGET_H
define WIDGET_H
include
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget parent = nullptr);
~Widget();
private slots:
void on_pushButton_clicked();
private:
Ui::Widget ui;
};
endif // WIDGET_H
#### 4.3.2 widget.cpp实现文件
include "widget.h"
include "ui_widget.h"
include
include
include
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_pushButton_clicked()
{
// 弹出文件对话框,让用户选择一个文件
QString path = QFileDialog::getOpenFileName(this);
// 构造QFileInfo对象
QFileInfo fileInfo(path);
// 打印文件的各种属性信息
qDebug()
就写这么多吧,内容比较基础,适合入门回顾。有补充的地方欢迎留言一起完善。
评论 (0)
暂无评论