《Qt从零入门系列(十二):Qt文件操作详解——从QFile读写到QFileInfo与记事本实战》

文件操作,是每一款桌面应用都绕不开的命根子。小到读写一段文本,大到管理复杂的配置文件、做数据持久化,背后都站着它。Qt作为跨平台开发框架,最拿得出手的优势之一,就是给了一套统一的文件操作API,把C/C++原生库和系统API之间的平台鸿沟一把填平,Linux下的open/read/write,Windows下的CreateFile,到了Qt这里,统统不用再操心。Qt诞生于1991年,比C++标准库的标准化进程还早,这套文件系统封装经过长期迭代优化,和QString、QByteArray这些Qt核心类无缝集成,用起来比C++17才引入的std::filesystem更顺手、更高效。

本文会把Qt文件操作的核心知识系统过一遍:从I/O设备的继承体系,到QFile类的完整API用法;从零实现一个支持打开和保存的简易记事本,再到用QFileInfo类获取文件属性。所有内容都配着完整可运行的代码,当作Qt入门的复习资料正合适,帮你快速捡回文件操作的核心逻辑,也顺手避开那些常见的坑。

目录

一、认识Qt文件系统------从I/O设备到QFile

[1.1 Qt中的I/O设备继承体系](#1.1 Qt中的I/O设备继承体系)

[1.2 QFile的两个常用子类](#1.2 QFile的两个常用子类)

二、QFile核心API------文件如何打开、读取与写入

[2.1 QFile构造函数](#2.1 QFile构造函数)

[2.2 open():打开文件的基本方式](#2.2 open():打开文件的基本方式)

[2.3 从QFile中读取文件内容](#2.3 从QFile中读取文件内容)

[2.3.1 read():读取指定数量的数据](#2.3.1 read():读取指定数量的数据)

[2.3.2 readLine():按行读取文件](#2.3.2 readLine():按行读取文件)

[2.3.3 readAll():一次读取全部内容](#2.3.3 readAll():一次读取全部内容)

[2.4 写入文件:保存数据到磁盘](#2.4 写入文件:保存数据到磁盘)

[2.5 close():文件使用完成后的关闭操作](#2.5 close():文件使用完成后的关闭操作)

三、文件读写实战:实现一个简易记事本

[3.1 从创建工程到搭建界面](#3.1 从创建工程到搭建界面)

[3.1.1 mainwindow.h:声明窗口功能](#3.1.1 mainwindow.h:声明窗口功能)

[3.1.2 mainwindow.cpp:实现窗口初始化](#3.1.2 mainwindow.cpp:实现窗口初始化)

[3.2 打开文件:将内容读取到编辑器](#3.2 打开文件:将内容读取到编辑器)

[3.3 保存文件:将编辑内容写回磁盘](#3.3 保存文件:将编辑内容写回磁盘)

[3.4 简易记事本运行效果](#3.4 简易记事本运行效果)

四、QFileInfo:获取文件详细信息

[4.1 QFileInfo构造函数](#4.1 QFileInfo构造函数)

[4.2 QFileInfo常用API](#4.2 QFileInfo常用API)

[4.3 通过代码获取文件信息](#4.3 通过代码获取文件信息)

[4.3.1 widget.h:声明文件信息相关功能](#4.3.1 widget.h:声明文件信息相关功能)

[4.3.2 widget.cpp:实现文件信息获取](#4.3.2 widget.cpp:实现文件信息获取)

[4.3.3 运行效果](#4.3.3 运行效果)

五、Qt文件操作小结


一、认识Qt文件系统------从I/O设备到QFile

Qt作为通用跨平台开发库,在文件系统这块给的能力相当完整,读写文件、获取文件信息、复制重命名、遍历目录,日常用得到的,它几乎全包了。

在Qt出现之前,文件操作基本靠两条路:一条是C语言标准库的fopen/fclose/fread/fwrite系列,另一条是操作系统的原生API。这两条路都有明显的短板。C标准库功能有限,拿不到文件的详细属性;系统API则完全不讲跨平台,Linux下写的代码,搬到Windows上直接歇菜。

Qt诞生于1991年,比C++标准的正式发布(1998年)还早。它的文件系统封装经过三十多年的迭代优化,不仅把跨平台问题解决得干干净净,还跟QString、QByteArray这些Qt核心类无缝集成。虽然C++17引入了std::filesystem,但Qt的文件操作API在易用性、功能完整性和与Qt生态的兼容性上,依然有明显优势。所以在Qt项目里,强烈推荐直接用Qt自己的文件操作类。

Qt文件操作的核心流程,跟原生方式完全一致,都是"打开 → 读/写 → 关闭"那一套。区别只在于,它把这些操作封装成了更顺手的类和方法,用起来省心不少。

1.1 Qt中的I/O设备继承体系

Qt里所有输入输出设备,追根溯源,都继承自同一个祖宗QIODevice。这个基类定下了所有I/O设备的通用接口:打开、关闭、读、写,一个不落。文件、网络套接字、串口、蓝牙、进程通信、内存缓冲区,统统算I/O设备,所以它们全都挂在QIODevice名下。完整的继承关系,长这样:

cpp 复制代码
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还备了两个非常实用的子类,专门收拾特定场景下的麻烦事。

QTemporaryFile:临时文件专业户。

它生来就是造临时文件的。最省心的一点是对象一销毁,对应的临时文件自动删除,片甲不留。你存完临时数据,拍拍屁股走人就行,不用惦记着手动清理。少写一行清理代码,就少埋一个忘记删文件的坑。

QSaveFile:安全写入的守门员。

它玩的是"先写临时文件,写完再替换原文件"的原子性策略。写数据的时候,它绝不直接碰原文件,而是先把内容一股脑写进一个临时文件。等所有数据都成功落盘了,再删掉原文件,把临时文件重命名顶上去。

这套路数能有效挡住写入过程中程序崩溃、或者突然断电导致原文件损坏的风险。Java、Redis这些系统,用的也是类似的思路。先把新版本在边上备好,确认无误再一键换防,稳。

二、QFile核心API------文件如何打开、读取与写入

QFile是Qt文件操作的核心角色。打开、读、写、关闭,一整套流程它全包了。绝对路径、相对路径都能用,跟Qt其他类配合起来也特别顺手。

2.1 QFile构造函数

QFile的构造函数不复杂,最常用的就一个:

cpp 复制代码
QFile(const QString &name)

参数name是文件路径,绝对路径也好,相对路径也罢,都能传。绝对路径长这样:C:/test.txt;相对路径则是相对于程序当前运行目录来算的。

这里有个坑得拎出来敲一下:构造函数只是把QFile对象造出来,并不会真的去打开文件。 你想读写,必须老老实实调open()方法。光建对象不开门,文件永远在门外站着。

2.2 open():打开文件的基本方式

打开文件,靠的就是open()方法。原型长这样:

cpp 复制代码
virtual bool open(QIODevice::OpenMode mode) override

返回值是bool:true表示打开成功,false表示失败。失败的原因五花八门------文件不存在、权限不够、路径写错了,都可能让你吃闭门羹。

参数mode是文件的打开模式,类型是QIODevice::OpenMode枚举的组合。想同时指定多个模式?用按位或 | 把它们串起来就行。

常用的打开模式,列在下面:

模式常量 数值 说明
QIODevice::NotOpen 0x0000 未打开
QIODevice::ReadOnly 0x0001 只读模式,文件必须存在
QIODevice::WriteOnly 0x0002 只写模式,文件不存在就创建;已存在则清空原有内容(除非同时指定 Append 模式)
QIODevice::ReadWrite 0x0003 读写模式,相当于ReadOnly | WriteOnly
QIODevice::Append 0x0004 追加模式,所有写入都落在文件末尾
QIODevice::Truncate 0x0008 截断模式,打开时清空原有内容
QIODevice::Text 0x0010 文本模式,自动转换换行符:Windows下把\n转成\r\n,Linux下保持\n 不变
QIODevice::Unbuffered 0x0020 无缓冲模式,绕过系统缓冲区,直接读写磁盘
QIODevice::NewOnly 0x0040 仅新建模式,只有文件不存在时才创建并打开;已存在则打开失败
QIODevice::ExistingOnly 0x0080 仅打开已存在文件模式,文件不存在就打开失败

看个例子,以只读文本模式打开文件:

cpp 复制代码
QFile file("test.txt");
bool ret = file.open(QIODevice::ReadOnly | QIODevice::Text);
if (!ret) {
    qDebug() << "打开文件失败";
    return;
}
2.3 从QFile中读取文件内容

QFile 读文件的路子不止一条,不同场景,用不同招。

2.3.1 read():读取指定数量的数据
cpp 复制代码
qint64 read(char *data, qint64 maxSize);
QByteArray read(qint64 maxSize);

两个重载,各管一摊。

  • 第一个版本,把最多maxSize个字节的数据,塞进data指向的缓冲区里,返回实际读到的字节数。用这个版本,缓冲区得自己提前备好,读多少、读到哪,心里得有数。
  • 第二个版本就省事多了:把最多maxSize个字节直接读进一个QByteArray对象并返回。不用手动管理缓冲区,QByteArray自己会打理,拿来就能用。日常读写,大多数人更偏爱这一版。
2.3.2 readLine():按行读取文件
cpp 复制代码
qint64 readLine(char *data, qint64 maxSize);
QByteArray readLine(qint64 maxSize = 0);

按行读,一次一行,读到换行符\n或者凑满maxSize个字节就收手。

这招最适合文本文件,配置文件、日志文件,这些按行组织的内容,用readLine一行一行往外捞,逻辑天然对齐,处理起来也顺手。

2.3.3 readAll():一次读取全部内容
cpp 复制代码
QByteArray readAll();

一口气把文件全部内容读完,返回一个QByteArray。这是最简单粗暴的读法,小文件用它,一行代码搞定,省心。

但有个前提得记牢:大文件别用readAll。 它会把整个文件一股脑加载进内存,文件稍微大点,内存占用就蹭蹭往上涨,轻则卡顿,重则直接把程序撑爆。大文件还是老老实实分块读,别贪这一时的方便。

一个重要提示:QByteArray转QString,比你想的还方便。

QByteArray可以非常顺滑地变成QString。QString本身就提供了直接接受QByteArray的构造函数和赋值运算符:

cpp 复制代码
QByteArray byteArray = file.readAll();
QString text = byteArray; // 直接转换

// 或者更简洁的写法
QString text = file.readAll();

读出来就是字符串,转换这一步几乎不用你操心。

不过注意,这种转换默认走的是UTF-8编码。 要是文件用的是别的编码,比如GBK,那就得请出QTextCodec来做转换了。编码不对,读出来的就是一堆乱码,别怪文件,怪编码没对上。

2.4 写入文件:保存数据到磁盘

写文件用write(),一共三个重载版本:

cpp 复制代码
qint64 write(const char *data, qint64 maxSize);
qint64 write(const char *data);
qint64 write(const QByteArray &byteArray);

返回值是实际写入的字节数,写失败了就返回-1。

参数data是要写进去的内容,C风格字符串也行,QByteArray对象也行,来者不拒。

但有个关键点必须拎出来说:QString不能直接当write()的参数。 你想写字符串,得先把它转成QByteArray。推荐用toUtf8(),把QString转成UTF-8编码的QByteArray,这是跨平台兼容性最好的一种方式:

cpp 复制代码
QString text = "Hello World";
file.write(text.toUtf8());

当然,别的编码也能用,比如toLatin1()或者toLocal8Bit()。但用之前得掂量掂量,这些编码跨平台时容易出幺蛾子,换个系统、换个环境,乱码就找上门了。没特殊需求的话,toUtf8()是最稳的选择,别给自己找麻烦。

2.5 close():文件使用完成后的关闭操作

文件操作做完,最后一件事千万别忘,关文件。调用close()方法:

cpp 复制代码
virtual void close();

关文件这个动作,本质上是把操作系统为这个文件分配的文件描述符表项给释放掉。每个进程的文件描述符表都是有固定上限的。Linux默认通常是1024。你光开不关,文件描述符就一个接一个地漏,漏到最后,表满了,后面再想打开任何文件,门都没有。这就是典型的文件描述符泄漏。

有人可能想:程序退出的时候,操作系统不是会自动把所有打开的文件都关掉吗?那还费劲手动关干嘛?

话是没错,但别指望操作系统给你兜底。养成手动关文件的好习惯,在长时间运行的服务程序里尤其重要。 一个跑几个月都不带重启的服务,文件开开关关成千上万次,你每漏一个,就离"打开失败"近一步。到时候排查起来,哭都来不及。用完就关,这是规矩。

三、文件读写实战:实现一个简易记事本

光讲API不过瘾,我们直接上手做一个完整的项目,一个简易记事本,支持打开和保存文本文件。把前面学的QFile那套东西,全都串起来用一遍。

3.1 从创建工程到搭建界面

先创建一个Qt Widgets Application项目,基类选QMainWindow。主窗口的骨架,就靠它撑起来。

3.1.1 mainwindow.h:声明窗口功能
cpp 复制代码
#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继承自QMainWindow,这是主窗口程序的标准起手式。两个槽函数handleAction1和handleAction2,分别对应"打开"和"保存"两个菜单项的动作。名字起得随意了点,后面完全可以改成onOpen、onSave之类更见名知意的叫法,但功能上先跑通再说。

QPlainTextEdit* edit被拎出来当成员变量,不是随手一放。它得在槽函数里被访问,如果只放在构造函数里当局部变量,出了那个作用域就找不着了。提到成员变量的位置上,两个槽函数随时都能伸手拿到它,这是Qt里处理控件跨函数访问的常规操作。

3.1.2 mainwindow.cpp:实现窗口初始化

界面搭建的活儿,全在构造函数里完成。菜单栏、菜单项、文本编辑框,一股脑儿安排到位,再把信号槽接上,记事本的骨架就立起来了。

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;
}

这段代码里,几个动作环环相扣。

先设窗口标题,再拿菜单栏,this->menuBar()会帮你把菜单栏准备好,不用自己new。接着建一个"文件"菜单挂上去,再往里塞"打开"和"保存"两个QAction。到这里,菜单部分就齐了。

然后轮到文本编辑框。QPlainTextEdit被new出来,赋给成员变量edit,再把字体调到20像素,看着不费眼。最后用setCentralWidget把它安到窗口正中央,成了整个记事本的主战场。

收尾一步,connect把两个QAction的triggered信号,分别接到handleAction1和handleAction2上。菜单一点,槽函数就动,界面和逻辑就此接上了电。

3.2 打开文件:将内容读取到编辑器

轮到handleAction1()登场,把"打开文件"这条路走通:

cpp 复制代码
#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);
}
3.3 保存文件:将编辑内容写回磁盘
cpp 复制代码
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步里那个toUtf8(),QString不能直接往write()里塞,必须先转成QByteArray。UTF-8编码在这儿是跨平台最稳的选择,写出来的文件到哪儿都不会乱码。

3.4 简易记事本运行效果

编译跑起来,一个带"文件"菜单的窗口就立起来了,菜单里躺着"打开"和"保存"两项。

点"打开",文件选择对话框弹出来。选一个文本文件,内容立刻铺满编辑框,状态栏同时把文件的完整路径报出来。

点"保存",保存对话框登场。定好路径和文件名,编辑框里的内容就哗哗写进文件。

一个能读能写、有菜单有反馈的简易记事本,到这儿就算完工了。麻雀虽小,QFile的打开、读取、写入、关闭,全套流程都跑了一遍,算是一次完整的实战。

四、QFileInfo:获取文件详细信息

QFileInfo是Qt专门用来获取文件和目录属性信息的类。文件名、文件大小、路径、类型、创建时间、修改时间、访问时间......你能想到的属性,它基本都能捞出来。在C++17引入std::filesystem之前,想拿这些信息,非得跟操作系统原生API打交道,平台一换,代码就得重写。QFileInfo给了一套跨平台的统一接口,一处编写,到处能跑。

4.1 QFileInfo构造函数

最常用的两个构造函数:

cpp 复制代码
QFileInfo(const QString &file);
QFileInfo(const QFile &file);

参数file可以是文件路径,也可以是一个现成的QFile对象。给路径就按路径查,给对象就按对象查,两条路都通。

4.2 QFileInfo常用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。

后缀这一组特别值得玩味:suffix只认最后一个点后面的东西,completeSuffix则把从第一个点开始往后的一串全算上。差之毫厘,谬以千里,用哪个得看你要什么。

路径相关:

  • 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:声明文件信息相关功能
cpp 复制代码
#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

头文件很常规,就一个按钮的槽函数on_pushButton_clicked,等着被点击触发。

4.3.2 widget.cpp:实现文件信息获取
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();
}

逻辑很直白:点一下按钮,弹个文件选择框,选中之后,用路径造一个QFileInfo。接下来就是"体检报告"时间,文件名、后缀、路径、大小、是不是普通文件、是不是目录、存不存在,挨个查一遍,全部打到控制台上。一个对象,七项属性,文件的底细摸得清清楚楚。

4.3.3 运行效果

编译跑起来,点按钮,选一个文件,控制台就会吐出一串信息。比如选中ui_widget.h,输出大致是这样:

cpp 复制代码
文件名: "ui_widget.h"
文件后缀: "h"
文件路径: "C:/Users/18106/Desktop/QT/qt/code/build-QFileInfo-Desktop_Qt_5_14_2_MinGW_64_bit-Debug"
文件大小: 1526 字节
是否为普通文件: true
是否为目录: false
是否存在: true

一条条看下来:文件名带后缀,后缀单独摘出来,路径不含文件名,大小精确到字节,类型判断、存在判断,全是明明白白。QFileInfo就这么点事,一个对象,把文件的里里外外都给你翻出来了。

五、Qt文件操作小结

这篇从理论到实战,把Qt文件操作的核心知识完整走了一遍。下面这些,是必须牢牢握在手里的东西。

Qt文件系统的核心优势,就三个字:跨平台。 它跟QString、QByteArray这些Qt核心类无缝集成,功能完善,错误处理也友好。比起C标准库和系统原生API,用起来省心得多。

I/O设备的继承体系,得心里有数。 所有I/O设备都从QIODevice派生,QFile又从QFileDevice继承而来。搞清楚这层关系,Qt I/O系统那套统一设计的思想,你才算摸到了门。

QFile的核心操作流程,一条都不能漏:

  • 构造函数只负责创建对象,不打开文件。想读写,必须老老实实调open()。
  • open()必须指定正确的打开模式,返回值也要认真处理,别打开了没打开都不知道。
  • 读文件:小文件直接readAll(),文本文件按行读就用readLine()。
  • 写文件:QString不能直接往里塞,必须先转成QByteArray。优先用toUtf8(),跨平台最稳。
  • close()必须手动调。不关,文件描述符就一个接一个地漏,漏到最后,什么都打不开。

特殊场景,有特殊工具:

  • 临时文件用QTemporaryFile,对象一销毁,文件自动删除,省心。
  • 重要文件写入用QSaveFile,先写临时文件再原子替换,原文件损坏的风险被它挡在门外。

**文件信息获取,交给QFileInfo。**文件名、大小、路径、时间、类型,跨平台统一接口,不用再跟操作系统原生API纠缠。

实战部分,我们做了一个简易记事本。 QFileDialog选文件,QStatusBar报状态,QPlainTextEdit展示内容,打开和保存的完整逻辑一条龙跑通。这套组合拳打下来,文件操作的基本盘就稳了。

这些东西,是Qt桌面开发的地基。几乎每一个Qt应用,都绕不开文件操作。把这些吃透,你才能写出功能完善、稳定可靠的Qt程序。


写到这里,Qt文件操作这一篇就收尾了。

回头看看,其实核心就那几件事:QFile负责打开、读写、关闭,QFileInfo负责查户口,QSaveFile和QTemporaryFile在特殊场景兜底,再加上QFileDialog和QStatusBar一配合,一个像模像样的记事本就能跑起来。

文件操作这个东西,平时不起眼,可但凡是个正经桌面应用,就绕不开它。配置要存、日志要写、用户数据要持久化,程序得靠它记住点东西,不然每次重启都像失忆。把这一块吃透,你写的程序才算真正有了"记忆"。

动手把那个简易记事本敲一遍,再试着自己加点功能,比如另存为、最近打开、自动保存,感受一下文件操作从"能用"到"好用"的变化。后面遇到更复杂的场景,心里就有底了。

如果这篇文章对你有帮助,别忘了点个赞、点个收藏、点个关注。你的每一次反馈,都是我继续硬核输出的最大动力。我们下篇见。

相关推荐
青少儿编程课堂1 小时前
树上启发式合并详解:子树颜色众数统计与复杂度拆解
c++·python·算法·bfs·信息学竞赛
路弥行至1 小时前
【Head First 设计模式】第 2 章:观察者模式 —— 用现代 C++ 重新解读“交互对象的松耦合
c++·经验分享·笔记·观察者模式·设计模式·入门教程·headfirst
YYYing.2 小时前
【设计模式系列 (九) 】装饰器模式
c++·后端·设计模式·装饰器模式·c/c++
时间的拾荒人2 小时前
Qt 界面布局与容器控件详解:从分组框到布局管理器
开发语言·qt·面试
elseif1232 小时前
【2026 CSP-J】【逐题精讲】超详细(15道选择,3道阅读,2道完善)
java·开发语言·c++·算法·csp
智鸟科技GemeOpen开发者智能设备2 小时前
MQTT智能插座GSPM1B2 · 开发者实战指南
java·开发语言·python·物联网
Fluxproxy2 小时前
Python BeautifulSoup4 超全实战教程|解决网页乱码、标签匹配、层级查找、数据提取难题
开发语言·python
殷色玫瑰3 小时前
C语言编译和链接:从 .c到 .exe,程序到底经历了什么?
linux·c语言·c++·算法