一、Qt文件系统概述:QFile、QDir、QFileInfo、QIODevice的继承关系与核心职责
做Qt开发这么多年,文件操作几乎是每个项目都绕不开的坎。我记得刚入行那会儿,接手一个老项目,里面文件读写代码写得那叫一个乱——有人用C标准库的fopen,有人用Qt的QFile,还有人自己封装了一层。后来我花了整整两天时间,把所有文件操作统一成了Qt的这套体系。嗯,今天就跟大家聊聊Qt文件系统的这几个核心类。
1.1 从QIODevice说起:一切文件操作的根基
先看这张继承关系图,你就能明白这几个类是怎么串起来的。
说白了,QIODevice 是所有输入输出设备的抽象基类。它定义了读写的基本接口——read、write、open、close 这些。你想想看,不管是文件、网络套接字还是内存缓冲区,底层操作其实都差不多:打开、读写、关闭。QIODevice 就是把这些共性抽了出来。
核心职责一句话:QIODevice 提供统一的读写接口,所有具体设备类都继承自它。
1.2 QFile:最常用的文件操作类
QFile 继承自 QFileDevice,而 QFileDevice 又继承自 QIODevice。我个人的习惯是,只要涉及本地文件读写,首选 QFile。为什么?因为它把文件打开、读写、关闭这些操作封装得特别干净。
来看一个最简单的例子:
// 打开文件并读取全部内容
QFile file("config.ini");
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
qWarning() << "文件打开失败:" << file.errorString();
return;
}
QByteArray data = file.readAll();
file.close();
嗯,这里要注意:open 函数一定要检查返回值。我在项目中遇到过好几次,因为路径写错或者权限不足,文件打开失败,结果程序直接崩溃。后来我养成了习惯——每次 open 之后必做检查。
小技巧:QFile 支持两种模式——文本模式(Text)和二进制模式。读文本文件时加上 QIODevice::Text 标志,Qt 会自动处理换行符的跨平台差异。Windows 上是 \r\n,Linux 上是 \n,Qt 帮你搞定。
1.3 QDir:目录操作的瑞士军刀
QDir 不继承 QIODevice,它是一个独立的工具类。专门用来处理目录路径、遍历文件、创建删除目录这些事。
我曾经接手过一个项目,里面有个功能需要扫描某个目录下所有 .log 文件。原代码写了一大堆平台相关的 API,Windows 用 FindFirstFile,Linux 用 opendir。我直接换成 QDir,十行代码搞定:
QDir dir("/var/log");
QStringList filters;
filters << "*.log";
dir.setNameFilters(filters);
QFileInfoList list = dir.entryInfoList();
for (const QFileInfo &info : list) {
qDebug() << "找到日志文件:" << info.absoluteFilePath();
}
你想想看,跨平台代码最怕的就是这种系统调用。用 QDir 之后,Windows、Linux、macOS 上跑得一模一样,省心多了。
避坑指南:我曾经在遍历目录时忘了设置过滤器,结果把 "." 和 ".." 也遍历出来了。记得用 entryInfoList() 时加上 QDir::Files 或 QDir::Dirs 标志,或者用 setNameFilters 过滤掉特殊目录。
1.4 QFileInfo:文件信息的查询利器
QFileInfo 也是个独立类。它不负责读写文件内容,只负责查询文件的元信息——大小、修改时间、权限、后缀名等等。
说实话,这个类特别实用。比如你要判断一个文件是否存在,或者获取文件的后缀名来决定用什么方式打开:
QFileInfo info("document.pdf");
if (info.exists()) {
qDebug() << "文件名:" << info.fileName();
qDebug() << "后缀名:" << info.suffix();
qDebug() << "文件大小:" << info.size() << "字节";
qDebug() << "最后修改:" << info.lastModified().toString("yyyy-MM-dd hh:mm:ss");
}
为什么要把 QFileInfo 单独拎出来?因为很多时候你只是想知道文件的信息,并不想打开它。比如做一个文件管理器,你总不能在列表里把每个文件都 open 一遍吧?那性能就太差了。
1.5 四个类的核心职责对比
为了方便记忆,我整理了一张表:
| 类名 | 继承关系 | 核心职责 | 典型场景 |
|---|---|---|---|
| QIODevice | 基类 | 定义读写接口,提供缓冲区管理 | 所有IO操作的抽象层 |
| QFile | QIODevice → QFileDevice → QFile | 文件的打开、读写、关闭 | 读写配置文件、日志文件、二进制数据 |
| QDir | 独立类(不继承QIODevice) | 目录路径操作、文件遍历、目录创建删除 | 扫描目录、管理文件列表、路径拼接 |
| QFileInfo | 独立类(不继承QIODevice) | 查询文件元信息(大小、时间、权限等) | 文件属性查看、文件类型判断 |
1.6 实际项目中的组合用法
在实际项目中,这三个类经常配合使用。我举个例子:
// 遍历目录下所有 .txt 文件,读取内容并统计行数
QDir dir("C:/data");
QStringList filters;
filters << "*.txt";
dir.setNameFilters(filters);
QFileInfoList files = dir.entryInfoList(QDir::Files);
int totalLines = 0;
for (const QFileInfo &info : files) {
QFile file(info.absoluteFilePath());
if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
while (!file.atEnd()) {
file.readLine();
totalLines++;
}
file.close();
}
}
qDebug() << "总行数:" << totalLines;
你看,QDir 负责找文件,QFileInfo 提供文件路径,QFile 负责读取内容。各司其职,配合得天衣无缝。
总结一下:QIODevice 是底层抽象,QFile 是文件读写主力,QDir 管目录操作,QFileInfo 查文件信息。把这四个类搞明白,Qt 文件操作你就掌握了八成。
嗯,这一章就到这里。记住我说的——文件打开一定要检查返回值,遍历目录记得过滤特殊项。这些都是我踩过的坑,你就不用再踩一遍了。