QT入门第十天:文件操作(下)文件信息与目录操作 | 零基础学QT
前言
昨天我们学习了文件操作的上篇:QFile文件读写、QTextStream文本流、QDataStream数据流。
今天我们继续学习文件操作的下篇,内容包括:
- QFileInfo:获取文件的详细信息(大小、时间、权限等)
- QDir:目录操作(创建、删除、遍历目录)
- QTemporaryFile:临时文件
- QFileSystemWatcher:文件监控
- 综合实战:简易文件浏览器
学完这两篇,QT的文件操作你就基本掌握了!
一、QFileInfo 文件信息
1.1 什么是QFileInfo
QFileInfo是用来获取文件信息的类。它可以告诉你关于一个文件的各种信息:
- 文件叫什么名字
- 文件在哪个目录
- 文件有多大
- 文件什么时候创建的、什么时候修改的
- 是文件还是目录
- 有没有读写权限
- 等等...
💡 理解:QFile就像一个文件操作工具(打开、读写),QFileInfo就像一个文件信息查询工具(查属性)。
1.2 基本用法
cpp
#include <QFileInfo>
#include <QDebug>
// 创建QFileInfo对象
QFileInfo info("test.txt");
// 获取各种信息
qDebug() << "文件名:" << info.fileName();
qDebug() << "文件路径:" << info.filePath();
qDebug() << "绝对路径:" << info.absoluteFilePath();
qDebug() << "文件大小:" << info.size() << "字节";
qDebug() << "是否存在:" << info.exists();
qDebug() << "是文件吗:" << info.isFile();
qDebug() << "是目录吗:" << info.isDir();
1.3 文件名称相关
cpp
QFileInfo info("C:/Users/xxx/Documents/report.txt");
qDebug() << info.fileName(); // "report.txt" (文件名+后缀)
qDebug() << info.baseName(); // "report" (文件名,不含后缀)
qDebug() << info.suffix(); // "txt" (后缀名)
qDebug() << info.completeSuffix(); // "txt" (完整后缀)
qDebug() << info.path(); // "C:/Users/xxx/Documents" (路径)
qDebug() << info.absolutePath(); // 绝对路径
qDebug() << info.absoluteFilePath(); // 绝对路径+文件名
💡 小技巧:用
baseName()和suffix()可以很方便地分离文件名和后缀。
1.4 文件时间
cpp
QFileInfo info("test.txt");
// 创建时间
qDebug() << "创建时间:" << info.birthTime();
// 最后修改时间
qDebug() << "修改时间:" << info.lastModified();
// 最后访问时间
qDebug() << "访问时间:" << info.lastRead();
// 最后元数据修改时间
qDebug() << "元数据修改时间:" << info.metadataChangeTime();
这些返回的都是QDateTime对象,可以用toString()格式化:
cpp
QDateTime time = info.lastModified();
qDebug() << time.toString("yyyy-MM-dd hh:mm:ss");
// 输出类似:2024-01-15 14:30:25
1.5 文件类型判断
cpp
QFileInfo info("xxx");
info.isFile(); // 是普通文件吗?
info.isDir(); // 是目录吗?
info.isSymLink(); // 是符号链接吗?
info.isExecutable(); // 是可执行文件吗?
info.isReadable(); // 可读吗?
info.isWritable(); // 可写吗?
info.isHidden(); // 是隐藏文件吗?
1.6 权限判断
cpp
QFileInfo info("test.txt");
// 检查所有者权限
if (info.permission(QFile::ReadOwner)) {
qDebug() << "所有者可读";
}
// 也可以一次检查多个权限
if (info.permission(QFile::ReadOwner | QFile::WriteOwner)) {
qDebug() << "所有者可读写";
}
权限类型有:
- QFile::ReadOwner / WriteOwner / ExeOwner(所有者)
- QFile::ReadUser / WriteUser / ExeUser(用户)
- QFile::ReadGroup / WriteGroup / ExeGroup(组)
- QFile::ReadOther / WriteOther / ExeOther(其他)
1.7 刷新信息
如果文件在程序运行过程中被修改了,QFileInfo的信息不会自动更新,需要手动刷新:
cpp
QFileInfo info("test.txt");
// ... 文件被修改了 ...
info.refresh(); // 刷新信息
二、QDir 目录操作
2.1 什么是QDir
QDir是QT中用来操作目录的类,可以:
- 查看目录里有什么文件
- 创建和删除目录
- 重命名目录
- 过滤和排序文件
- 获取各种系统目录
💡 理解:QDir就像一个文件夹操作工具,可以浏览文件夹、创建文件夹、删除文件夹。
2.2 基本用法
cpp
#include <QDir>
#include <QDebug>
// 创建QDir对象,指向当前目录
QDir dir;
// 或者指定路径
QDir dir2("C:/Users/xxx/Documents");
// 检查目录是否存在
if (dir.exists()) {
qDebug() << "目录存在";
}
// 获取当前路径
qDebug() << dir.currentPath();
2.3 遍历目录内容
获取目录下的所有文件和子目录:
cpp
QDir dir("C:/Users/xxx/Documents");
// 获取所有条目(文件+目录)
QStringList entries = dir.entryList();
// 遍历输出
for (const QString &entry : entries) {
qDebug() << entry;
}
2.4 过滤和排序
entryList()支持过滤和排序:
cpp
QDir dir("C:/Users/xxx/Documents");
// 只显示文件,不显示目录,按名称排序
QStringList files = dir.entryList(
QDir::Files, // 过滤:只显示文件
QDir::Name // 排序:按名称
);
常用过滤标志:
| 标志 | 说明 |
|---|---|
| QDir::Files | 只显示文件 |
| QDir::Dirs | 只显示目录 |
| QDir::AllEntries | 显示所有(文件+目录) |
| QDir::NoDotAndDotDot | 不显示.和... |
| QDir::Hidden | 显示隐藏文件 |
| QDir::Readable | 只显示可读的 |
| QDir::Writable | 只显示可写的 |
常用排序标志:
| 标志 | 说明 |
|---|---|
| QDir::Name | 按名称排序 |
| QDir::Time | 按时间排序 |
| QDir::Size | 按大小排序 |
| QDir::Type | 按类型排序 |
| QDir::Unsorted | 不排序 |
| QDir::Reversed | 反向排序 |
多个标志用 | 连接:
cpp
// 显示所有文件(不包括.和..),按大小从大到小排序
QStringList files = dir.entryList(
QDir::Files | QDir::NoDotAndDotDot,
QDir::Size | QDir::Reversed
);
2.5 名称过滤
还可以用通配符过滤文件名:
cpp
QDir dir("C:/Users/xxx/Documents");
// 只显示txt文件
QStringList filters;
filters << "*.txt";
dir.setNameFilters(filters);
QStringList txtFiles = dir.entryList(QDir::Files);
也可以多个过滤条件:
cpp
filters << "*.txt" << "*.doc" << "*.pdf";
2.6 创建目录
cpp
QDir dir;
// 创建一个目录
if (dir.mkdir("newFolder")) {
qDebug() << "创建成功";
} else {
qDebug() << "创建失败(可能已存在)";
}
// 创建多级目录(比如 a/b/c,父目录不存在也会一起创建)
if (dir.mkpath("a/b/c")) {
qDebug() << "多级目录创建成功";
}
💡 区别:
mkdir():只能创建一级目录,父目录必须存在mkpath():可以创建多级目录,父目录不存在会自动创建
2.7 删除目录
cpp
QDir dir;
// 删除一个空目录
if (dir.rmdir("emptyFolder")) {
qDebug() << "删除成功";
}
// 删除多级空目录
if (dir.rmpath("a/b/c")) {
qDebug() << "多级目录删除成功";
}
⚠️ 注意:rmdir()只能删除空目录!如果目录里有文件,删不掉。
如果要删除非空目录,需要先删除里面的所有文件,或者用更高级的方法。
2.8 重命名目录
cpp
QDir dir;
dir.rename("oldName", "newName");
2.9 目录路径操作
cpp
QDir dir("C:/Users/xxx/Documents");
// 切换到上级目录
dir.cdUp(); // 现在指向 C:/Users/xxx
// 切换到子目录
dir.cd("Documents"); // 又回到 C:/Users/xxx/Documents
// 判断是不是根目录
qDebug() << dir.isRoot();
// 目录名
qDebug() << dir.dirName(); // "Documents"
2.10 常用系统目录
QDir提供了一些静态方法获取常用目录:
cpp
// 当前工作目录
qDebug() << QDir::currentPath();
// 用户主目录
qDebug() << QDir::homePath();
// 临时文件目录
qDebug() << QDir::tempPath();
// 根目录
qDebug() << QDir::rootPath();
这些都是静态方法,直接用类名调用就行。
2.11 计算目录大小
遍历目录下所有文件,计算总大小:
cpp
qint64 dirSize(const QString &path) {
QDir dir(path);
qint64 size = 0;
// 遍历所有文件
QFileInfoList fileInfos = dir.entryInfoList(QDir::Files);
for (const QFileInfo &info : fileInfos) {
size += info.size();
}
// 递归遍历子目录
QFileInfoList dirInfos = dir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);
for (const QFileInfo &info : dirInfos) {
size += dirSize(info.absoluteFilePath());
}
return size;
}
三、QTemporaryFile 临时文件
3.1 什么是临时文件
临时文件就是用完就删的文件,常用于:
- 临时保存数据
- 程序间交换数据
- 缓存
QT提供了QTemporaryFile类,非常方便:
- 自动生成唯一的文件名(不会冲突)
- 文件关闭后自动删除
- 不用自己操心清理
3.2 基本用法
cpp
#include <QTemporaryFile>
#include <QTextStream>
#include <QDebug>
// 创建临时文件
QTemporaryFile tempFile;
// 打开文件
if (tempFile.open()) {
qDebug() << "临时文件路径:" << tempFile.fileName();
// 写入内容
QTextStream out(&tempFile);
out << "这是临时文件的内容";
// 关闭文件(关闭后会自动删除!)
tempFile.close();
}
💡 注意:QTemporaryFile关闭后会自动删除文件。如果想保留文件,需要调用setAutoRemove(false)。
3.3 不自动删除
如果你想让临时文件保留下来:
cpp
QTemporaryFile tempFile;
tempFile.setAutoRemove(false); // 关闭后不自动删除
if (tempFile.open()) {
// 写入...
tempFile.close();
// 文件还在,可以继续用
}
3.4 指定文件名模板
默认文件名是随机的,你也可以指定模板:
cpp
// 模板:myapp_XXXXXX.txt
// XXXXXX会被替换成随机字符
QTemporaryFile tempFile("myapp_XXXXXX.txt");
四、QFileSystemWatcher 文件监控
4.1 什么是文件监控
QFileSystemWatcher可以监控文件或目录的变化:
- 文件被修改了
- 文件被删除了
- 目录里新增了文件
- 目录里删除了文件
当变化发生时,会发出信号通知你。
💡 应用场景:
- 监控配置文件,修改后自动重新加载
- 监控文件夹,有新文件自动处理
- 文件被意外修改时提醒
4.2 基本用法
cpp
#include <QFileSystemWatcher>
#include <QDebug>
// 创建监控对象
QFileSystemWatcher *watcher = new QFileSystemWatcher(this);
// 添加要监控的文件
watcher->addPath("config.ini");
// 添加要监控的目录
watcher->addPath("dataFolder");
// 连接信号:文件变化时触发
connect(watcher, &QFileSystemWatcher::fileChanged,
this, [=](const QString &path){
qDebug() << "文件变化了:" << path;
// 重新加载文件...
});
// 连接信号:目录变化时触发
connect(watcher, &QFileSystemWatcher::directoryChanged,
this, [=](const QString &path){
qDebug() << "目录变化了:" << path;
// 重新扫描目录...
});
4.3 常用方法
cpp
// 添加监控路径
watcher->addPath("file.txt");
watcher->addPath("folder");
// 批量添加
QStringList paths;
paths << "a.txt" << "b.txt";
watcher->addPaths(paths);
// 移除监控
watcher->removePath("file.txt");
// 查看监控了哪些文件
qDebug() << watcher->files();
// 查看监控了哪些目录
qDebug() << watcher->directories();
4.4 注意事项
- 文件被删除后监控会失效:如果监控的文件被删了,需要重新添加
- 性能考虑:不要监控太多文件,可能会影响性能
- 跨平台:不同平台的监控机制可能有差异
五、综合实战:简易文件浏览器
我们来做一个简易的文件浏览器,可以浏览目录、查看文件信息。
5.1 完整代码
cpp
#include <QMainWindow>
#include <QListWidget>
#include <QLineEdit>
#include <QLabel>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QPushButton>
#include <QFileInfo>
#include <QDir>
#include <QMessageBox>
class FileBrowser : public QMainWindow
{
Q_OBJECT
public:
FileBrowser(QWidget *parent = nullptr) : QMainWindow(parent) {
setWindowTitle("简易文件浏览器");
resize(800, 600);
// 中心部件
QWidget *central = new QWidget(this);
setCentralWidget(central);
QVBoxLayout *mainLayout = new QVBoxLayout(central);
// 地址栏
QHBoxLayout *pathLayout = new QHBoxLayout();
m_pathEdit = new QLineEdit(this);
m_backBtn = new QPushButton("←", this);
m_backBtn->setFixedWidth(40);
pathLayout->addWidget(m_backBtn);
pathLayout->addWidget(m_pathEdit);
mainLayout->addLayout(pathLayout);
// 文件列表
m_fileList = new QListWidget(this);
mainLayout->addWidget(m_fileList);
// 状态栏(显示文件信息)
m_statusLabel = new QLabel("就绪", this);
mainLayout->addWidget(m_statusLabel);
// 连接信号槽
connect(m_backBtn, &QPushButton::clicked,
this, &FileBrowser::goBack);
connect(m_pathEdit, &QLineEdit::returnPressed,
this, &FileBrowser::goToPath);
connect(m_fileList, &QListWidget::itemDoubleClicked,
this, &FileBrowser::onItemDoubleClicked);
connect(m_fileList, &QListWidget::itemClicked,
this, &FileBrowser::onItemClicked);
// 初始显示用户主目录
m_currentDir = QDir::homePath();
updateList();
}
private slots:
// 返回上级
void goBack() {
QDir dir(m_currentDir);
if (dir.cdUp()) {
m_currentDir = dir.absolutePath();
updateList();
}
}
// 跳转到指定路径
void goToPath() {
QString path = m_pathEdit->text();
QDir dir(path);
if (dir.exists()) {
m_currentDir = dir.absolutePath();
updateList();
} else {
QMessageBox::warning(this, "错误", "路径不存在!");
}
}
// 双击条目
void onItemDoubleClicked(QListWidgetItem *item) {
QString name = item->text();
if (name == "..") {
goBack();
return;
}
QString fullPath = m_currentDir + "/" + name;
QFileInfo info(fullPath);
if (info.isDir()) {
// 是目录,进入
m_currentDir = fullPath;
updateList();
} else {
// 是文件,显示信息
QMessageBox::information(this, "文件信息",
QString("文件名:%1\n大小:%2 字节\n修改时间:%3")
.arg(info.fileName())
.arg(info.size())
.arg(info.lastModified().toString("yyyy-MM-dd hh:mm:ss"))
);
}
}
// 单击条目(显示文件大小)
void onItemClicked(QListWidgetItem *item) {
QString name = item->text();
if (name == "." || name == "..") {
m_statusLabel->setText(name);
return;
}
QString fullPath = m_currentDir + "/" + name;
QFileInfo info(fullPath);
if (info.isFile()) {
m_statusLabel->setText(
QString("%1 - %2 字节")
.arg(name)
.arg(info.size())
);
} else {
m_statusLabel->setText(name + " - 文件夹");
}
}
private:
// 更新文件列表
void updateList() {
m_pathEdit->setText(m_currentDir);
m_fileList->clear();
QDir dir(m_currentDir);
// 获取所有条目(文件+目录)
QFileInfoList entries = dir.entryInfoList(
QDir::AllEntries | QDir::NoDot, // 不显示.
QDir::DirsFirst | QDir::Name // 目录在前,按名称排序
);
for (const QFileInfo &info : entries) {
QListWidgetItem *item = new QListWidgetItem();
if (info.isDir()) {
item->setText("📁 " + info.fileName());
} else {
item->setText("📄 " + info.fileName());
}
m_fileList->addItem(item);
}
// 统计
int fileCount = dir.entryList(QDir::Files).count();
int dirCount = dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot).count();
m_statusLabel->setText(
QString("%1 个文件,%2 个文件夹")
.arg(fileCount)
.arg(dirCount)
);
}
private:
QLineEdit *m_pathEdit;
QPushButton *m_backBtn;
QListWidget *m_fileList;
QLabel *m_statusLabel;
QString m_currentDir;
};
5.2 功能说明
这个简易文件浏览器有这些功能:
- ✅ 浏览目录(双击进入文件夹)
- ✅ 返回上级目录
- ✅ 地址栏跳转
- ✅ 目录和文件用图标区分
- ✅ 单击显示文件大小
- ✅ 双击文件显示详细信息
- ✅ 状态栏显示统计信息
虽然简单,但核心的文件浏览功能都有了!
六、今日总结
今天我们学习了文件操作的下篇,主要是文件信息和目录操作。
知识点汇总
| 类 | 用途 | 特点 |
|---|---|---|
| QFileInfo | 文件信息 | 查询文件属性(大小、时间、权限等) |
| QDir | 目录操作 | 遍历、创建、删除目录 |
| QTemporaryFile | 临时文件 | 自动生成文件名,自动删除 |
| QFileSystemWatcher | 文件监控 | 监控文件/目录变化,信号通知 |
重要概念
- ✅ QFileInfo:获取文件的各种信息(名称、大小、时间、权限、类型)
- ✅ QDir:目录操作(遍历、过滤、排序、创建、删除)
- ✅ entryList / entryInfoList:获取目录内容,支持过滤和排序
- ✅ mkdir / mkpath:创建目录(mkpath支持多级)
- ✅ rmdir / rmpath:删除目录(只能删空目录)
- ✅ 临时文件:QTemporaryFile,自动命名,自动删除
- ✅ 文件监控:QFileSystemWatcher,监控变化,信号通知
经验分享
- QFileInfo很实用:获取文件信息不用自己写代码,直接用QFileInfo
- entryInfoList比entryList更方便:直接得到QFileInfo列表,不用再一个个创建
- mkpath比mkdir好用:可以创建多级目录,不用操心父目录是否存在
- 删除目录要小心:rmdir只能删空目录,非空目录要先删里面的文件
- 临时文件很方便:QTemporaryFile自动管理,不用操心清理
- 文件监控慎用:不要监控太多文件,注意性能
- 路径分隔符用 /:QT里统一用 / 就行,会自动转换
七、明日预告
明天我们将学习QT数据库编程。
内容包括:
- QT的SQL模块
- SQLite数据库入门
- 数据库的增删改查
- QSqlTableModel模型
- 综合实战:学生管理系统
数据库是很多应用的核心,明天我们一起来学习!
📝 学习建议:文件操作是基本功,一定要练熟。
练习建议:
- 把今天的文件浏览器代码敲一遍运行看看
- 试试给文件浏览器加一个"新建文件夹"功能
- 试试写一个程序,统计某个目录下所有文件的总大小
- 试试用QFileSystemWatcher监控一个文件夹,有变化时打印信息
文件操作上下两篇都学完了,你已经掌握了QT文件操作的核心内容!明天我们继续学数据库,继续加油!💪