文件操作是桌面应用的基石——无论是读写配置文件、处理日志,还是实现数据持久化,都离不开它。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多年迭代,不仅完美解决了跨平台问题,还与QStringQByteArray等核心类无缝集成。虽然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();
          }
[AFFILIATE_SLOT_2]

6. 总结

本文系统讲解了Qt文件操作的核心知识:从I/O设备继承体系,到QFile的打开、读、写、关闭完整API,再到通过实战实现简易记事本,最后介绍了QFileInfo获取文件属性的方法。与C++标准库或Java、Python、Go等语言的文件操作相比,Qt的API在跨平台兼容性和与Qt生态的集成度上具有独特优势。掌握这些内容,你就能在Qt项目中轻松应对各种文件操作场景。

在这里插入图片描述在这里插入图片描述

艾莉丝努力练剑

C/C++ & Linux 底层探索者 | 一个正在努力练剑的技术博主


【关注】 跟随我一起深耕技术领域,见证每一次成长。
❤️ 【点赞】 让优质内容被更多人看见,让知识传递更有力量。
【收藏】 把核心知识点存好,在需要时随时查、随时用。
【评论】 分享你的经验或疑问,评论区一起交流避坑!

不要忘记给博主“一键四连”哦!

“今日练剑达成!”

“技术之路难免有困惑,但同行的人会让前进更有方向。”

博主在这里放了一只小狗,大家看完了摸摸小狗放松一下吧!
૮₍ ˶ ˊ ᴥ ˋ˶₎ა

QIODevice::NotOpenQIODevice::ReadOnlyQIODevice::WriteOnlyAppendQIODevice::ReadWriteQIODevice::AppendQIODevice::TruncateQIODevice::Text\n\r\n\nQIODevice::UnbufferedQIODevice::NewOnlyQIODevice::ExistingOnly在这里插入图片描述