如何使用C++17的std::filesystem进行递归目录遍历?

在C++17之后,标准库提供了头文件,它让文件系统操作变得轻而易举。下面我们将演示如何利用std::filesystem的递归遍历功能,列举指定目录下的所有文件与子目录,并对每个文件输出其大小、类型以及最后修改时间。

#include <iostream>
#include <iomanip>
#include <filesystem>
#include <chrono>
#include <ctime>

namespace fs = std::filesystem;

// 将std::chrono::file_clock时间转换为可读字符串
std::string format_time(const fs::file_time_type& ftime)
{
    auto sctp = std::chrono::time_point_cast<std::chrono::system_clock::duration>(
        ftime - fs::file_time_type::clock::now() + std::chrono::system_clock::now());
    std::time_t cftime = std::chrono::system_clock::to_time_t(sctp);
    std::tm tm = *std::localtime(&cftime);
    char buf[100];
    std::strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &tm);
    return std::string(buf);
}

int main()
{
    std::string path;
    std::cout << "请输入要遍历的目录路径: ";
    std::getline(std::cin, path);

    if (!fs::exists(path)) {
        std::cerr << "路径不存在!\n";
        return 1;
    }

    std::cout << "\n--- 目录内容列表 ---\n";
    std::cout << std::left << std::setw(40) << "路径" << std::setw(15) << "类型" << std::setw(10) << "大小(B)" << "修改时间" << '\n';
    std::cout << std::string(90, '-') << '\n';

    for (const auto& entry : fs::recursive_directory_iterator(path))
    {
        std::string type;
        if (entry.is_regular_file())   type = "文件";
        else if (entry.is_directory()) type = "目录";
        else if (entry.is_symlink())   type = "符号链接";
        else                           type = "其它";

        uintmax_t size = entry.is_regular_file() ? entry.file_size() : 0;
        std::string mtime = format_time(entry.last_write_time());

        std::cout << std::left << std::setw(40) << entry.path().string() << std::setw(15) << type << std::setw(10) << size << mtime << '\n';
    }

    return 0;
}

代码要点解析

  1. 命名空间别名
    namespace fs = std::filesystem; 使后续代码更简洁。

  2. 递归遍历
    fs::recursive_directory_iterator 自动递归访问所有子目录。若想只列出顶层目录,使用 fs::directory_iterator 即可。

  3. 文件类型判断
    entry.is_regular_file(), entry.is_directory(), entry.is_symlink() 等成员函数可判断不同的文件系统对象类型。

  4. 文件大小
    只有常规文件(不是目录或符号链接)才有 file_size()。对于目录,我们通常把大小设为0。

  5. 时间格式化
    C++17 的 file_time_typestd::chrono::system_clock 不兼容,必须先进行时钟转换。示例函数 format_time 把时间转换为易读的字符串。

  6. 异常处理
    这里没有显式捕获异常,recursive_directory_iterator 在遇到无权限文件时会抛出 std::filesystem::filesystem_error。在生产代码中建议使用 try-catcherror_code 参数来避免程序崩溃。

运行示例

$ ./fs_list
请输入要遍历的目录路径: /usr/include

--- 目录内容列表 ---
路径                                         类型           大小(B)    修改时间
------------------------------------------------------------------------------------------
/usr/include/c++/12.2.1/iostream                 文件           1024     2025-04-10 09:13:57
/usr/include/c++/12.2.1/iostream.h               文件           2048     2025-04-10 09:13:57
/usr/include/c++/12.2.1/bits/ios_base.h          文件           3072     2025-04-10 09:13:57
...

小结

通过 `

`,C++ 让文件系统操作变得异常方便。递归遍历只需一行迭代器声明,且代码可读性极高。掌握这些基本技巧后,你就能在自己的项目中灵活处理文件读取、目录扫描、权限判断等任务。祝你编码愉快!

发表评论