QT 目录操作(QDir 类)及展示系统文件实战


QDir 是 Qt 中用于目录操作的核心类,提供了跨平台的方式来访问目录结构、操作路径、遍历文件等。它使用 / 作为统一的目录分隔符,Qt 会自动将其转换为底层操作系统的分隔符。


一、常用 API 速查

1.1 构造与路径操作

API 说明
QDir() 构造指向当前工作目录的 QDir
QDir(const QString &path) 构造指向指定路径的 QDir
path() 获取当前路径(可能是相对路径)
setPath(const QString &path) 设置新路径
absolutePath() 获取绝对路径
canonicalPath() 获取规范路径(解析符号链接,消除 ...
dirName() 获取目录名(绝对路径中最后一个元素)
isAbsolute() / isRelative() 判断路径是绝对还是相对
makeAbsolute() 将相对路径转为绝对路径
isRoot() 判断是否为根目录
isReadable() 判断目录是否可读

1.2 目录导航

API 说明
cd(const QString &dirName) 进入子目录(类似 shell 的 cd
cdUp() 返回上级目录(等价于 cd("..")

说明: cd()cdUp() 改变的是 QDir 对象内部记录的路径,不影响操作系统的工作目录。

1.3 目录创建与删除

API 说明
mkdir(const QString &dirName) 创建单个子目录(父目录必须存在)
mkpath(const QString &dirPath) 递归创建多级目录(自动创建不存在的父目录)
rmdir(const QString &dirName) 删除空目录
rmpath(const QString &dirPath) 递归删除空目录(从最深层开始)
removeRecursively() 删除目录及其所有内容(⚠️ 慎用!不可逆)
rename(const QString &oldName, const QString &newName) 重命名目录
exists() 判断目录是否存在
isEmpty(QDir::Filters) 判断目录是否为空
refresh() 从磁盘重新读取目录数据

1.4 文件与目录内容遍历

API 说明
entryList(filters, sortFlags) 获取目录下所有条目的文件名列表(QStringList
entryInfoList(filters, sortFlags) 获取目录下所有条目的详细信息列表(QFileInfoList
count() 获取目录中条目数量
operator[](int) 按索引获取条目名称
filePath(const QString &fileName) 拼接相对路径
absoluteFilePath(const QString &fileName) 拼接绝对路径
relativeFilePath(const QString &fileName) 获取相对于当前目录的路径
remove(const QString &fileName) 删除指定文件

1.5 过滤器与排序

API 说明
setFilter(QDir::Filters filters) 设置属性过滤器
setNameFilters(const QStringList &filters) 设置名称过滤器(通配符模式)
setSorting(QDir::SortFlags sort) 设置排序方式

1.6 常用静态方法

API 说明
QDir::current() / QDir::currentPath() 应用程序的工作目录
QDir::home() / QDir::homePath() 用户主目录
QDir::root() / QDir::rootPath() 根目录
QDir::temp() / QDir::tempPath() 系统临时目录
QDir::setCurrent(const QString &path) 设置应用程序工作目录
QDir::cleanPath(const QString &path) 清理路径(去除多余的 /..
QDir::toNativeSeparators(const QString &path) 转换为本地路径分隔符(如 Windows 的 \
QDir::fromNativeSeparators(const QString &path) 从本地分隔符转为 /
QDir::separator() 返回平台原生路径分隔符(静态)
QDir::match(filter, fileName) 测试文件名是否匹配通配符模式
QDir::match(filters, fileName) 同时测试多个通配符模式
QDir::drives() 返回系统所有逻辑驱动器列表
QDir::isAbsolutePath(path) / isRelativePath(path) 判断路径类型(静态)

1.7 遍历模式(iterator)

Qt 还提供了 QDirIterator 用于更灵活的递归遍历:

API 说明
QDirIterator(path, filters, flags) 构造目录迭代器
hasNext() 是否还有下一个条目
next() 前进到下一个条目,返回文件路径
fileName() 获取当前条目文件名
filePath() 获取当前条目完整路径
fileInfo() 获取当前条目的 QFileInfo

遍历标志:

标志 说明
QDirIterator::NoIteratorFlags 默认(不递归)
QDirIterator::Subdirectories 递归遍历所有子目录
QDirIterator::FollowSymlinks 跟随符号链接
// 递归遍历示例
QDirIterator it("/path/to/dir", QDir::Files, QDirIterator::Subdirectories);
while (it.hasNext()) {
    it.next();
    qDebug() << it.filePath();
}

二、Filter 过滤器枚举详解

QDir::Filter 用于 entryList()entryInfoList() 过滤条目,可以用 | 组合使用:

枚举值 说明
QDir::Dirs 列出目录
QDir::AllDirs 列出所有目录,不对目录名过滤
QDir::Files 列出文件
QDir::Drives 列出逻辑驱动器(Unix 下忽略)
QDir::NoSymLinks 不列出符号链接
QDir::NoDotAndDotDot 不列出 ...
QDir::NoDot 不列出 .
QDir::NoDotDot 不列出 ..
QDir::AllEntries 列出所有条目(Dirs | Files | Drives)
QDir::Readable 只列出有读权限的条目
QDir::Writable 只列出有写权限的条目
QDir::Executable 只列出有执行权限的条目
QDir::Hidden 包含隐藏文件
QDir::System 列出系统文件
QDir::CaseSensitive 过滤器大小写敏感
QDir::Modified 仅列出已修改的文件(与 Qt 资源系统配合)

常用组合示例:

// 列出所有文件(不含目录和 . / ..)
QDir dir("/home/user");
QStringList files = dir.entryList(QDir::Files | QDir::NoDotAndDotDot);

// 列出所有隐藏文件
QStringList hidden = dir.entryList(QDir::Files | QDir::Hidden | QDir::NoDotAndDotDot);

// 列出所有条目按修改时间排序
QFileInfoList list = dir.entryInfoList(QDir::AllEntries | QDir::NoDotAndDotDot,
                                        QDir::Time | QDir::Reversed);

三、SortFlag 排序枚举详解

枚举值 说明
QDir::Name 按名称排序
QDir::Time 按修改时间排序(最新在前)
QDir::Size 按文件大小排序
QDir::Type 按文件类型(扩展名)排序
QDir::Unsorted 不排序(保持文件系统原始顺序)
QDir::DirsFirst 目录排在文件前面
QDir::DirsLast 目录排在文件后面
QDir::Reversed 反向排序
QDir::IgnoreCase 排序时忽略大小写
QDir::LocaleAware 按本地化规则排序(使用当前区域设置)

四、案例一:递归计算目录大小

main.cpp

#include <QCoreApplication>
#include <QDir>
#include <QStringList>
#include <QtDebug>

/**
 * @brief GetDirFileInfoSizeFunc  递归计算目录下所有文件的总大小
 * @param qpath  要计算的目录路径
 * @return       该目录下所有文件的字节总数
 */
qint64 GetDirFileInfoSizeFunc(const QString &qpath)
{
    // QDir 类专门用来操作路径名称或底层文件系统,
    // 可以使用相对或绝对路径来指向一个文件/目录
    QDir qdirs(qpath);

    qint64 qsize = 0;  // 存放目录占据的空间

    // QFileInfo 类提供文件系统中文件的名称、路径、位置、访问权限、文件类型等信息
    // entryInfoList 获取过滤后目录下的文件信息列表
    foreach (QFileInfo finfo, qdirs.entryInfoList(QDir::Files)) {
        qsize = qsize + finfo.size();
    }

    // 递归处理子目录
    // QDir::Dirs 列出目录,QDir::NoDotAndDotDot 不列出 . 和 ..
    foreach (QString sDir, qdirs.entryList(QDir::Dirs | QDir::NoDotAndDotDot)) {
        qsize = qsize + GetDirFileInfoSizeFunc(qpath + QDir::separator() + sDir);
    }

    // 格式化输出:自动选择合适单位
    QString unit = "B";
    qint64 currentdirsize = qsize;

    if (currentdirsize > 1024) {
        currentdirsize = currentdirsize / 1024;
        unit = "KB";
    }
    if (currentdirsize > 1024) {
        currentdirsize = currentdirsize / 1024;
        unit = "MB";
    }
    if (currentdirsize > 1024) {
        currentdirsize = currentdirsize / 1024;
        unit = "GB";
    }
    if (currentdirsize > 1024) {
        currentdirsize = currentdirsize / 1024;
        unit = "TB";
    }

    qDebug().noquote() << "目录占据空间为:" << currentdirsize << unit
                        << "\t" << qPrintable(qpath);

    return qsize;
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    QString strPath = QDir::currentPath();  // 获取当前工作目录
    qDebug() << "当前目录为:" << strPath << endl;

    // 调用此函数计算目录占据空间的大小
    GetDirFileInfoSizeFunc(strPath);

    return a.exec();
}

效果:

运行结果1

运行结果2

运行结果3


五、案例二:简易文件浏览器

dialog.h

#ifndef DIALOG_H
#define DIALOG_H

#include <QDialog>
#include <QListWidget>       // 列表框
#include <QListWidgetItem>
#include <QLineEdit>         // 单行输入框
#include <QDir>              // 目录操作
#include <QFileInfo>         // 文件信息
#include <QFileInfoList>
#include <QVBoxLayout>
#include <QIcon>
#include <QStringList>

/**
 * @brief Dialog 主窗口类
 *
 * 一个基于 QDir 的简易文件/目录浏览器:
 * - 顶部 QLineEdit 显示当前所在目录的绝对路径,支持手动输入路径后回车跳转;
 * - 下方 QListWidget 列出当前目录下的所有条目(目录在前、文件在后);
 * - 双击列表中的任意条目即可进入对应的子目录。
 */
class Dialog : public QDialog
{
    Q_OBJECT

public:
    Dialog(QWidget *parent = nullptr);
    ~Dialog();

private:
    QLineEdit    *fileLineEdit;       // 显示当前目录路径
    QListWidget  *fileListWidget;     // 列表框:展示当前目录下的目录和文件
    QVBoxLayout  *glayout;            // 垂直布局管理器

public:
    /**
     * @brief 将文件信息列表逐项显示到列表框中
     * @param list 待显示的文件信息列表
     */
    void dispfileinfolist(QFileInfoList list);

public slots:
    /**
     * @brief 列出指定目录 dir 下的所有条目并显示
     * @param dir 目标目录
     */
    void dispDir(QDir dir);

    /**
     * @brief 双击列表项后,进入该项对应的子目录并刷新显示
     * @param item 被双击的列表项
     */
    void dispDirShow(QListWidgetItem *item);
};

#endif // DIALOG_H

dialog.cpp

#include "dialog.h"

Dialog::Dialog(QWidget *parent)
    : QDialog(parent)
{
    resize(500, 350);
    setWindowTitle("QDir类综合控件应用测试");

    // 创建控件:路径输入框(默认根目录 "/")、条目列表框
    fileLineEdit   = new QLineEdit("/");
    fileListWidget = new QListWidget;

    // 垂直布局
    glayout = new QVBoxLayout(this);
    glayout->addWidget(fileLineEdit);
    glayout->addWidget(fileListWidget);

    // 信号与槽连接
    // 回车 → 将输入框内容作为路径,显示其条目
    connect(fileLineEdit, SIGNAL(returnPressed()),
            this, SLOT(dispDir(QDir)));

    // 双击列表项 → 进入对应子目录
    connect(fileListWidget, SIGNAL(itemDoubleClicked(QListWidgetItem *)),
            this, SLOT(dispDirShow(QListWidgetItem *)));

    // 初始显示根目录 "/" 下的所有条目
    QString    root = "/";
    QDir       rootDir(root);
    QStringList strlist;
    strlist << "*";  // 通配符 "*":匹配所有名称

    QFileInfoList list = rootDir.entryInfoList(strlist);
    dispfileinfolist(list);
}

Dialog::~Dialog()
{
}

/**
 * @brief 将文件信息列表逐项添加到列表框中
 *
 * 目录条目使用文件夹图标,文件条目使用文件图标;
 * "." / ".." 等特殊目录也会一并显示(可在 dispDir 中通过
 * 指定过滤器 QDir::NoDotAndDotDot 排除)。
 */
void Dialog::dispfileinfolist(QFileInfoList list)
{
    fileListWidget->clear();  // 清空列表框,避免重复显示

    for (unsigned int i = 0; i < list.count(); i++) {
        QFileInfo tempfileinfo = list.at(i);
        QString   filename     = tempfileinfo.fileName();

        if (tempfileinfo.isDir()) {
            // 目录 → 使用文件夹图标
            QIcon ico("E:/qtCodeImg/dir.jpg");
            QListWidgetItem *temp = new QListWidgetItem(ico, filename);
            fileListWidget->addItem(temp);
        } else if (tempfileinfo.isFile()) {
            // 文件 → 使用文件图标
            QIcon ico("E:/qtCodeImg/file.jpg");
            QListWidgetItem *temp = new QListWidgetItem(ico, filename);
            fileListWidget->addItem(temp);
        }
    }
}

/**
 * @brief 列出指定目录下的所有条目并显示
 */
void Dialog::dispDir(QDir dir)
{
    QStringList strlist;
    strlist << "*";

    QFileInfoList fileinfolist =
        dir.entryInfoList(strlist, QDir::AllEntries, QDir::DirsFirst);

    dispfileinfolist(fileinfolist);
}

/**
 * @brief 双击列表项后进入对应子目录并刷新
 */
void Dialog::dispDirShow(QListWidgetItem *item)
{
    QDir    dir;
    QString str = item->text();           // 双击的条目名称
    dir.setPath(fileLineEdit->text());    // 以当前显示路径为基准
    dir.cd(str);                          // 切换到双击的目录

    // 更新路径输入框并刷新列表
    fileLineEdit->setText(dir.absolutePath());
    dispDir(dir);
}

效果:

文件浏览器效果


六、案例三:获取文件属性

dialog.h

#ifndef DIALOG_H
#define DIALOG_H

#include <QDialog>

#include <QLabel>
#include <QLineEdit>
#include <QCheckBox>
#include <QPushButton>

#include <QFileDialog>    // 文件对话框
#include <QFileInfo>      // 文件信息
#include <QDateTime>
#include <QHBoxLayout>
#include <QVBoxLayout>

class Dialog : public QDialog
{
    Q_OBJECT

public:
    Dialog(QWidget *parent = nullptr);
    ~Dialog();

private:
    // 文件路径
    QLabel      *labelfilename;
    QLineEdit   *qlineeditfilename;
    QPushButton *qpushbuttongetFilename;

    // 文件大小
    QLabel    *labelfilesize;
    QLineEdit *qlineeditfilesize;

    // 创建时间
    QLabel    *labelfilecreatetime;
    QLineEdit *qlineeditfilecreatetime;

    // 修改时间
    QLabel    *labelfilemoidfytime;
    QLineEdit *qlineeditfilemoidfytime;

    // 最后访问时间
    QLabel    *labelfileaccesstime;
    QLineEdit *qlineeditfileaccesstime;

    // 文件属性复选框
    QLabel      *qlabelfileattribute;
    QCheckBox   *qcheckboxfile;
    QCheckBox   *qcheckboxshide;
    QCheckBox   *qcheckboxreadable;
    QCheckBox   *qcheckboxwriteable;
    QCheckBox   *qcheckboxexecute;

    QPushButton *qpushbuttongetfileattributeinfo;

private slots:
    void getfilepathandname();        // 打开文件对话框选择文件
    void getfileattributeinfo();      // 获取并显示文件属性信息
};

#endif // DIALOG_H

dialog.cpp

#include "dialog.h"

Dialog::Dialog(QWidget *parent)
    : QDialog(parent)
{
    setWindowTitle("获取文件属性项目实战模块");

    labelfilename           = new QLabel("文件路径名称");
    qlineeditfilename       = new QLineEdit;
    qpushbuttongetFilename  = new QPushButton("打开文件...");

    labelfilesize           = new QLabel("文件容量大小:");
    qlineeditfilesize       = new QLineEdit;

    labelfilecreatetime     = new QLabel("文件创建时间:");
    qlineeditfilecreatetime = new QLineEdit;

    labelfilemoidfytime     = new QLabel("文件修改时间:");
    qlineeditfilemoidfytime = new QLineEdit;

    labelfileaccesstime     = new QLabel("文件访问时间:");
    qlineeditfileaccesstime = new QLineEdit;

    // 文件属性复选框
    qlabelfileattribute = new QLabel("文件属性");
    qcheckboxfile       = new QCheckBox("文件");
    qcheckboxshide      = new QCheckBox("隐藏属性");
    qcheckboxreadable   = new QCheckBox("只读属性");
    qcheckboxwriteable  = new QCheckBox("只写属性");
    qcheckboxexecute    = new QCheckBox("执行权限");

    qpushbuttongetfileattributeinfo = new QPushButton("获取文件属性的全部信息");

    // ========== 布局 ==========
    QGridLayout *glayout = new QGridLayout;
    glayout->addWidget(labelfilename,          0, 0);
    glayout->addWidget(qlineeditfilename,      0, 1);
    glayout->addWidget(qpushbuttongetFilename, 0, 2);

    glayout->addWidget(labelfilesize,              1, 0);
    glayout->addWidget(qlineeditfilesize,          1, 1, 1, 2);

    glayout->addWidget(labelfilecreatetime,        2, 0);
    glayout->addWidget(qlineeditfilecreatetime,    2, 1, 1, 2);

    glayout->addWidget(labelfilemoidfytime,        3, 0);
    glayout->addWidget(qlineeditfilemoidfytime,    3, 1, 1, 2);

    glayout->addWidget(labelfileaccesstime,        4, 0);
    glayout->addWidget(qlineeditfileaccesstime,    4, 1, 1, 2);

    // 文件属性标签水平布局
    QHBoxLayout *hlayout = new QHBoxLayout;
    hlayout->addWidget(qlabelfileattribute);
    hlayout->addStretch();

    // 复选框水平布局
    QHBoxLayout *hlayoutattribute = new QHBoxLayout;
    hlayoutattribute->addWidget(qcheckboxfile);
    hlayoutattribute->addWidget(qcheckboxshide);
    hlayoutattribute->addWidget(qcheckboxreadable);
    hlayoutattribute->addWidget(qcheckboxwriteable);
    hlayoutattribute->addWidget(qcheckboxexecute);
    hlayoutattribute->addStretch();

    // 按钮布局
    QGridLayout *glayoutbtn = new QGridLayout;
    glayoutbtn->addWidget(qpushbuttongetfileattributeinfo);

    // 垂直总布局
    QVBoxLayout *vlayout = new QVBoxLayout(this);
    vlayout->addLayout(glayout);
    vlayout->addLayout(hlayout);
    vlayout->addLayout(hlayoutattribute);
    vlayout->addLayout(glayoutbtn);

    // 信号与槽连接
    connect(qpushbuttongetFilename, SIGNAL(clicked()),
            this, SLOT(getfilepathandname()));
    connect(qpushbuttongetfileattributeinfo, SIGNAL(clicked()),
            this, SLOT(getfileattributeinfo()));
}

Dialog::~Dialog()
{
}

void Dialog::getfilepathandname()
{
    QString filePathName;
    filePathName = QFileDialog::getOpenFileName(
        this, "打开文件对话框", "/", "files(*)");
    qlineeditfilename->setText(filePathName);
}

void Dialog::getfileattributeinfo()
{
    QString  strfile = qlineeditfilename->text();
    QFileInfo qfi(strfile);

    // 获取文件属性信息
    qint64   filesize       = qfi.size();           // 文件大小
    QDateTime createtime    = qfi.birthTime();       // 创建时间(Qt 6+;Qt 5 用 created())
    QDateTime lastModifytime = qfi.lastModified();   // 最后修改时间
    QDateTime lastaccesstime = qfi.lastRead();       // 最后访问时间

    // 显示到对应输入框
    qlineeditfilesize->setText(QString::number(filesize));
    qlineeditfilecreatetime->setText(createtime.toString());
    qlineeditfilemoidfytime->setText(lastModifytime.toString());
    qlineeditfileaccesstime->setText(lastaccesstime.toString());

    // 文件属性复选框状态
    bool isFile       = qfi.isFile();
    bool isHidden     = qfi.isHidden();
    bool isReadable   = qfi.isReadable();
    bool isWritable   = qfi.isWritable();
    bool isExecutable = qfi.isExecutable();

    qcheckboxfile->setCheckState(isFile       ? Qt::Checked : Qt::Unchecked);
    qcheckboxshide->setCheckState(isHidden     ? Qt::Checked : Qt::Unchecked);
    qcheckboxreadable->setCheckState(isReadable   ? Qt::Checked : Qt::Unchecked);
    qcheckboxwriteable->setCheckState(isWritable   ? Qt::Checked : Qt::Unchecked);
    qcheckboxexecute->setCheckState(isExecutable ? Qt::Checked : Qt::Unchecked);
}

效果:

文件属性效果


七、打包成 EXE 一体文件步骤

7.1 构建 Release 版本

在 Qt Creator 中选择 Release 模式构建项目:

构建步骤

构建后在项目同级目录下会出现一个文件夹:
build-项目名-Desktop_Qt_5_12_8_MinGW_32_bit-Release

构建输出文件夹

7.2 下载 Enigma Virtual Box 打包工具

下载地址: https://enigmaprotector.com/en/downloads.html

Enigma 下载页面

7.3 使用 Enigma Virtual Box 打包

步骤一: 打开 Enigma Virtual Box,选择要封装的 EXE 主程序:

选择主程序

步骤二: 添加构建输出文件夹:

选择构建文件夹

步骤三: 选择构建好的 Release 文件夹:

确认文件夹

步骤四: 确认文件列表(包括 EXE 和所需的 DLL 文件):

文件列表确认

步骤五: 设置输出文件名,点击 Process 开始打包:

开始打包

步骤六: 打包完成后点击 Run 验证程序是否正常运行:

打包完成

步骤七: 验证通过——生成的即是可独立运行的 EXE 一体文件:

打包好的EXE

说明: Enigma Virtual Box 将 EXE 和所需 DLL 打包为单个文件,无需安装即可在未装 Qt 环境的 Windows 上运行。如需更精细的控制(如压缩、加密),可考虑使用 windeployqt + 其他打包工具(如 NSIS、Inno Setup)制作安装包。


小结

QDir 是 Qt 文件系统操作的核心入口,核心要点:

  1. 路径操作: QDir 使用 / 作为统一分隔符,自动适配平台;cd() / cdUp() 不改变系统工作目录
  2. 目录管理: mkdir() / mkpath() 创建目录,rmdir() / removeRecursively() 删除目录
  3. 内容遍历: entryList() 返回文件名列表,entryInfoList() 返回含详细信息的 QFileInfo 列表;QDirIterator 支持递归遍历
  4. 过滤器与排序: QDir::Filter(13种)和 QDir::SortFlag(10种)可灵活组合,精确控制输出
  5. 静态工具方法: currentPath() / homePath() / tempPath() 快速获取标准路径,toNativeSeparators() 处理路径格式
  6. 实战应用: 递归计算目录大小、文件浏览器、文件属性查看,覆盖了 QDir + QFileInfo + QFileDialog 的典型组合用法
Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐