3. QDir 与目录遍历:递归遍历、过滤器与文件监听
目录操作,说白了就是 Qt 里最基础也最容易踩坑的地方。我刚开始用 QDir 的时候,觉得这玩意儿不就是个文件夹浏览嘛,结果真到项目里,递归遍历卡死、过滤器漏文件、监听器不触发……各种问题全来了。今天咱们就把这些坑一个一个填上。
3.1 QDir 核心操作:别只会用 entryList
很多人一上来就调 entryList(),拿个 QStringList 就走。但 QDir 远不止这么简单。我习惯先搞清楚几个关键属性:
| 属性 | 作用 | 我常用的值 |
|---|---|---|
| setPath() | 设置目录路径 | 绝对路径,避免相对路径歧义 |
| setFilter() | 过滤条目类型 | QDir::Files | QDir::NoDotAndDotDot |
| setNameFilters() | 按文件名模式过滤 | {"*.txt", "*.log"} |
| setSorting() | 排序方式 | QDir::Name | QDir::DirsFirst |
exists() 检查路径是否有效。曾经有个项目,路径字符串末尾多了个空格,查了我两个小时。
3.2 递归遍历目录:别用递归函数硬写
递归遍历目录,最直接的想法就是写个递归函数,碰到子目录就调自己。但这样做有两个问题:一是深度太大会栈溢出,二是代码不好维护。
我推荐用 QDirIterator,它自带递归模式:
QDirIterator it("/path/to/dir", QDir::Files, QDirIterator::Subdirectories);
while (it.hasNext()) {
QString filePath = it.next();
// 处理文件
qDebug() << filePath;
}
你看,一行 QDirIterator::Subdirectories 就搞定了递归。内部用的是迭代器模式,不会爆栈。我在一个嵌入式项目里遍历过 10 万级文件目录,稳得很。
3.3 过滤器:别漏文件也别多文件
过滤器的坑,主要出在 QDir::Filters 和 QDir::NameFilters 的配合上。很多人只设了 nameFilters,忘了设 filter,结果把目录也列出来了。
我总结了一套「黄金组合」:
QDir dir("/data/logs");
dir.setFilter(QDir::Files | QDir::NoDotAndDotDot);
dir.setNameFilters({"*.log", "*.txt"});
QFileInfoList list = dir.entryInfoList();
这样只返回 .log 和 .txt 文件,不包含目录,也不包含 . 和 ..。
QDir::CaseInsensitive。
3.4 QFileSystemWatcher:监听文件变化
文件监听,说白了就是让程序「盯着」某个文件或目录,变了就通知你。QFileSystemWatcher 用起来很简单:
QFileSystemWatcher *watcher = new QFileSystemWatcher(this);
watcher->addPath("/path/to/watch");
connect(watcher, &QFileSystemWatcher::fileChanged,
this, [](const QString &path) {
qDebug() << "文件变了:" << path;
});
但这里有个大坑:QFileSystemWatcher 在文件被替换时可能丢失监听。比如编辑器保存文件时,先删除再创建,watcher 就失效了。
解决方案有两个:
- 方案一:监听目录而不是文件,用
directoryChanged信号,然后自己检查文件列表变化。 - 方案二:在
fileChanged触发后,重新addPath()一次。
我个人倾向方案一,更可靠:
watcher->addPath("/path/to/dir");
connect(watcher, &QFileSystemWatcher::directoryChanged,
this, [](const QString &dirPath) {
QDir dir(dirPath);
if (dir.exists("config.ini")) {
// 重新加载配置
}
});
3.5 知识结构图:目录操作全景
下面这张图把 QDir、QDirIterator、QFileSystemWatcher 的关系和典型用法串起来了。你想想看,从「创建目录对象」到「遍历文件」再到「监听变化」,其实是一条完整的数据流。
3.6 实战建议:目录操作的「三板斧」
最后,我把自己在项目中沉淀下来的三个习惯分享给你:
- 路径统一用正斜杠:Qt 内部会处理平台差异,但你自己写路径时,统一用 "/",别用 "\"。Windows 上也支持。
- 善用 QFileInfo:
entryInfoList()比entryList()好用得多,能直接拿到大小、修改时间、权限等信息,省得你再 stat 一次。 - 监听目录比监听文件靠谱:如前面所说,QFileSystemWatcher 监听目录的
directoryChanged信号,然后自己判断哪个文件变了,这样最稳定。