如何在C++17中使用 std::filesystem 遍历目录

在 C++17 标准中加入了 <filesystem> 头文件,它为文件系统操作提供了一套现代、跨平台的接口。下面将演示如何使用 std::filesystem::recursive_directory_iterator 来递归遍历一个目录,并打印出所有文件路径。示例代码兼顾了错误处理、文件属性检查以及路径格式化等细节。

#include <iostream>
#include <filesystem>
#include <string>

namespace fs = std::filesystem;

int main()
{
    // 1. 获取要遍历的根目录
    fs::path root_dir = fs::current_path(); // 也可以改为 fs::path("/some/path");

    // 2. 检查路径是否存在且为目录
    if (!fs::exists(root_dir)) {
        std::cerr << "路径不存在: " << root_dir << '\n';
        return 1;
    }
    if (!fs::is_directory(root_dir)) {
        std::cerr << "给定路径不是目录: " << root_dir << '\n';
        return 1;
    }

    // 3. 创建递归目录迭代器
    // 迭代器会自动忽略符号链接循环,除非你显式开启
    for (auto const &entry : fs::recursive_directory_iterator(root_dir)) {
        try {
            const fs::path &p = entry.path();

            // 打印相对路径,方便查看
            std::cout << std::setw(4) << entry.depth() << ' ' << p.filename() << '\n';

            // 根据需求可做进一步筛选,例如只打印 .cpp 文件
            if (p.extension() == ".cpp") {
                std::cout << "  -> C++ 源文件\n";
            }

            // 如果需要读取文件大小
            if (fs::is_regular_file(entry.status())) {
                std::uintmax_t sz = fs::file_size(p);
                std::cout << "    大小: " << sz << " 字节\n";
            }
        } catch (const fs::filesystem_error &e) {
            std::cerr << "访问错误: " << e.what() << '\n';
            // 继续遍历
        }
    }

    return 0;
}

关键点说明

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

  2. 递归迭代器
    fs::recursive_directory_iterator 会自动进入子目录。若想禁用符号链接递归,可使用 fs::directory_options::follow_directory_symlink 控制。

  3. 错误处理
    std::filesystem 的大部分操作会抛出 fs::filesystem_error。在遍历时使用 try‑catch 可以保证单个错误不会终止整个程序。

  4. 深度信息
    entry.depth() 返回从根目录开始的层级深度,便于输出树状结构。

  5. 文件属性
    fs::is_regular_file(entry.status()) 用来区分普通文件与目录。fs::file_size(p) 给出文件大小。

  6. 跨平台兼容
    该代码在 Windows、Linux 和 macOS 上均能正常编译运行,前提是编译器支持 C++17(如 GCC 8+、Clang 7+、MSVC 19.14+)。

扩展思路

  • 过滤器:可以用 fs::directory_options::skip_permission_denied 或自定义谓词来过滤特定文件类型或大小范围。
  • 异步遍历:结合 std::async 或线程池,对大型项目进行并行文件统计。
  • 路径规范化:使用 fs::weakly_canonical(p)fs::canonical(p) 解决相对路径与符号链接的混乱。

通过上述示例,你已经掌握了在 C++17 中使用 `

` 进行递归目录遍历的基本方法。可以在此基础上进一步开发更复杂的文件系统工具,例如文件备份、日志收集或资源管理器等。

发表评论