文件操作是桌面应用的基石——无论是读写配置文件、处理日志,还是实现数据持久化,都离不开它。Qt作为跨平台框架,提供了统一的文件API,彻底解决了C/C++原生库和系统API的平台兼容性问题。本文将系统讲解Qt文件操作的核心知识,涵盖I/O设备继承体系、QFile完整API、实战搭建简易记事本,以及QFileInfo文件信息获取,适合作为复习和快速上手的参考资料。


1. Qt文件系统概述:为什么选择Qt文件API?
在Qt诞生之前,文件操作主要依赖C标准库的fopen/fclose/fread/fwrite系列函数或操作系统原生API。前者功能有限,无法获取文件详细属性;后者则完全不具备跨平台性——Linux下的open/read/write代码无法直接在Windows的CreateFile上运行。Qt诞生于1991年,早于C++98标准,其文件系统封装经过30多年迭代,不仅完美解决了跨平台问题,还与QString、QByteArray等核心类无缝集成。虽然C++17引入了std::filesystem库,但Qt的API在易用性和生态兼容性上仍有明显优势,因此在Qt项目中强烈推荐使用Qt自身的文件操作类。
核心流程:Qt文件操作遵循“打开→读/写→关闭”的基本逻辑,与原生方式一致,但封装成了更易用的类和方法。

2. I/O设备继承体系:从QIODevice到QFile
Qt中所有输入输出设备都继承自QIODevice类,它定义了打开、关闭、读、写等通用接口。文件、网络套接字、串口、蓝牙、进程通信、内存缓冲区等都属于I/O设备。完整的继承关系如下:
QObject(Qt所有对象的基类)QIODevice(所有I/O设备的基类)QFileDevice(文件设备的基类)QFile(普通文件操作)QTemporaryFile(临时文件操作)QSaveFile(安全写文件)QAbstractSocket(网络套接字基类)QTcpSocket(TCP套接字)QUdpSocket(UDP套接字)QSerialPort(串口通信)QBluetoothSocket(蓝牙通信)QProcess(进程间通信)QBuffer(内存缓冲区操作)
其中QFile是我们最常用的文件操作类。此外,Qt还提供了两个实用的子类:QTemporaryFile用于创建临时文件,对象销毁时自动删除;QSaveFile采用“先写临时文件,写完再替换原文件”的原子性策略,避免写入过程中崩溃导致原文件损坏——这种安全写策略在Java、Redis等系统中也有广泛应用。
3. QFile核心API详解:从打开到关闭
3.1 构造函数与打开文件
QFile的构造函数最常用的是:
QFile(const QString &name) 参数为文件路径,支持绝对路径(如C:/test.txt)或相对路径。注意:构造函数只是创建对象,必须调用open()方法才能实际打开文件。打开文件使用open()方法,原型为:virtual bool open(QIODevice::OpenMode mode) override 返回bool值,true表示成功。常用的打开模式包括:| 模式常量 | 数值 | 说明 |
|---|---|---|
| 0x0000 | 未打开 | |
| 0x0001 | 只读模式,文件必须存在 | |
| 0x0002 | 只写模式,如果文件不存在则创建;如果文件已存在则清空原有内容(除非同时指定模式) | |
| 0x0003 | 读写模式,相当于`ReadOnly | |
| 0x0004 | 追加模式,所有写入操作都在文件末尾进行 | |
| 0x0008 | 截断模式,打开文件时清空原有内容 | |
| 0x0010 | 文本模式,自动转换换行符:在Windows下将转换为,在Linux下保持不变 | |
| 0x0020 | 无缓冲模式,绕过系统缓冲区,直接读写磁盘 | |
| 0x0040 | 仅新建模式,只有当文件不存在时才创建并打开;如果文件已存在则打开失败 | |
| 0x0080 | 仅打开已存在文件模式,如果文件不存在则打开失败 |
3.2 读文件:read、readLine与readAll
QFile提供了三种读方法:read()用于读取指定字节数,支持缓冲区或QByteArray形式(
qint64 read(char *data, qint64 maxSize);
QByteArray read(qint64 maxSize););readLine()按行读取,适合配置文件或日志(qint64 readLine(char *data, qint64 maxSize);
QByteArray readLine(qint64 maxSize = 0););readAll()一次性读取全部内容(QByteArray readAll();),适合小文件。⚠️ 注意:对于大文件,不要使用readAll(),否则可能导致内存占用过高。QByteArray可以方便地转换为QString:
QByteArray byteArray = file.readAll();
QString text = byteArray; // 直接转换
// 或者更简洁的写法
QString text = file.readAll(); 默认使用UTF-8编码,如果文件使用其他编码(如GBK),需要用QTextCodec进行转换。3.3 写文件与关闭
写文件使用write()方法:
qint64 write(const char *data, qint64 maxSize);
qint64 write(const char *data);
qint64 write(const QByteArray &byteArray); 返回值是实际写入的字节数。⚠️ 关键提示:QString不能直接作为write()的参数,必须先转换为QByteArray,推荐使用toUtf8()方法转为UTF-8编码:QString text = "Hello World";
file.write(text.toUtf8()); 文件操作完成后,必须调用close()方法关闭文件:virtual void close(); 关闭文件的本质是释放操作系统为该文件分配的文件描述符表项。每个进程的文件描述符表都有上限(Linux默认通常是1024),只打开不关闭会导致泄漏,最终耗尽资源。即使程序退出时操作系统会自动清理,养成手动关闭的好习惯仍然非常重要。4. 实战:简易记事本实现
下面通过一个完整的实战项目巩固QFile的使用。我们将实现一个简易记事本,支持打开和保存文本文件。
4.1 项目创建与界面搭建
创建一个Qt Widgets Application项目,基类选择QMainWindow。
- mainwindow.h头文件:
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include <QPlainTextEdit> 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 - mainwindow.cpp构造函数:
#include "mainwindow.h" #include "ui_mainwindow.h" #include <QMenuBar> #include <QMenu> #include <QAction> #include <QFont> 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; }
4.2 打开文件功能实现
实现handleAction1()槽函数:
#include <QFileDialog>
#include <QStatusBar>
#include <QFile>
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);
}4.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();
}4.4 运行效果
编译运行后,会出现一个带有“文件”菜单的窗口,包含“打开”和“保存”两个菜单项。点击“打开”弹出文件选择对话框,选择文本文件后内容会显示在编辑框中,状态栏显示文件路径。点击“保存”弹出保存对话框,编辑框中的内容被保存到指定文件。
[AFFILIATE_SLOT_1]5. QFileInfo文件信息类:获取文件属性
QFileInfo是Qt提供的用于获取文件和目录属性信息的类,可以获取文件名、大小、路径、类型、时间等各种属性。在C++17引入std::filesystem之前,获取这些属性必须使用操作系统原生API,而QFileInfo提供了跨平台的统一接口。
5.1 构造函数与常用API
最常用的构造函数:
QFileInfo(const QString &file);
QFileInfo(const QFile &file); 参数为文件路径或QFile对象。常用API包括:QString fileName() const:返回文件名(含后缀)QString baseName() const:返回基本名(不含后缀)QString completeBaseName() const:返回完整的基本名QString suffix() const:返回后缀名QString completeSuffix() const:返回完整后缀名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:返回时间信息(创建/修改/访问时间)
5.2 实战代码
下面通过一个简单例子演示QFileInfo的使用:
- widget.h头文件:
#ifndef WIDGET_H #define WIDGET_H #include <QWidget> 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 - widget.cpp实现文件:
#include "widget.h" #include "ui_widget.h" #include <QFileDialog> #include <QDebug> #include <QFileInfo> 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() << "文件名:" << fileInfo.fileName(); qDebug() << "文件后缀:" << fileInfo.suffix(); qDebug() << "文件路径:" << fileInfo.path(); qDebug() << "文件大小:" << fileInfo.size() << "字节"; qDebug() << "是否为普通文件:" << fileInfo.isFile(); qDebug() << "是否为目录:" << fileInfo.isDir(); qDebug() << "是否存在:" << fileInfo.exists(); }
6. 总结
本文系统讲解了Qt文件操作的核心知识:从I/O设备继承体系,到QFile的打开、读、写、关闭完整API,再到通过实战实现简易记事本,最后介绍了QFileInfo获取文件属性的方法。与C++标准库或Java、Python、Go等语言的文件操作相比,Qt的API在跨平台兼容性和与Qt生态的集成度上具有独特优势。掌握这些内容,你就能在Qt项目中轻松应对各种文件操作场景。



|
博主在这里放了一只小狗,大家看完了摸摸小狗放松一下吧! ૮₍ ˶ ˊ ᴥ ˋ˶₎ა
QIODevice::NotOpenQIODevice::ReadOnlyQIODevice::WriteOnlyAppendQIODevice::ReadWriteQIODevice::AppendQIODevice::TruncateQIODevice::Text\n\r\n\nQIODevice::UnbufferedQIODevice::NewOnlyQIODevice::ExistingOnly
浙公网安备 33010602011771号