17370845950

C++怎么遍历文件夹 C++ filesystem库操作目录与文件【C++17】
应使用 std::filesystem::recursive_directory_iterator 遍历子目录和文件,它自动深度优先遍历并支持跳过权限错误;需处理 filesystem_error 异常或设置 skip_permission_denied 选项。

怎么用 std::filesystem 遍历子目录和文件

直接用 std::filesystem::recursive_directory_iterator,它会自动进入子目录,按深度优先顺序返回所有 directory_entry。别手写递归——容易漏掉符号链接、权限错误或循环引用。

常见错误是没捕获异常:access_deniednot_a_directory 会抛 std::filesystem::filesystem_error,不处理就 crash。默认构造的迭代器不跳过异常,得手动加 try/catch 或用 std::filesystem::directory_options::skip_permission_denied

  • 用法示例:
    for (auto& entry : std::filesystem::recursive_directory_iterator(path, std::filesystem::directory_options::skip_permission_denied)) {
        if (entry.is_regular_f

    ile()) { std::cout << entry.path() << "\n"; } }
  • 想只遍历当前层?换用 std::filesystem::directory_iterator,它不进子目录
  • 路径末尾带斜杠不影响,但传入空字符串或非法路径会立即抛异常

std::filesystem::is_directoryis_regular_file 判断不准?

不是函数不准,是调用前没确认 entry 状态是否已缓存。directory_entry 默认惰性加载元数据,首次调用 is_* 才去查系统。如果中间路径被删/权限变,可能抛异常;更糟的是,某些平台(如 Windows)对符号链接默认不解析,is_directory() 返回 false 即使它指向一个目录。

  • 保险做法:先调 entry.status()entry.symlink_status(),再判断类型
  • 区分真实类型和链接目标:用 status() 查链接目标,symlink_status() 查链接本身
  • Windows *意:NTFS 重解析点(如 junction)会被 is_directory() 误判,必须用 symlink_status().type() == std::filesystem::file_type::directory

跨平台遍历时路径分隔符和编码问题

std::filesystem::path 内部统一用 / 存储,无论 Windows 还是 Linux,path.native() 才转成本地格式(Windows 上变成 \)。但真正要注意的是字符编码:Windows API 默认用当前代码页(如 GBK),而 C++17 标准要求 std::filesystem 接收 UTF-8 字符串(GCC/Clang)或宽字符(MSVC)。

  • Linux/macOS:传 UTF-8 std::string 安全
  • MSVC:推荐用 std::wstring 构造 path,否则含中文路径可能失败
  • 避免拼接路径用 +:用 / 操作符,例如 p / "sub" / "file.txt",它自动处理分隔符
  • 打印路径别直接 cout :用 p.string()(UTF-8)或 p.wstring()(宽字符)显式转换

性能差?大量小文件遍历时卡顿

慢通常不是 recursive_directory_iterator 本身的问题,而是每步都触发系统调用查元数据。比如只想要文件名,却反复调 entry.is_regular_file(),等于每个 entry 都 stat 一次。

  • 优化方法:用 entry.file_size() 前先确认类型,或批量用 std::filesystem::status(entry) 一次取回全部信息
  • 不需要递归?改用 directory_iterator + 手动栈管理,避免深度优先的隐式调用开销
  • Windows 上尤其明显:启用“8.3 短文件名”或杀软实时扫描会拖慢 10 倍以上,测试时关掉这些干扰项
  • 别在循环里反复构造 path 对象,复用变量减少临时对象分配

最常被忽略的一点:std::filesystem 在 GCC 需要链接 -lstdc++fs,Clang 要 -lc++fs,MSVC 默认开启但需确保项目设置为 C++17 或更高。忘了加链接选项,编译通过但运行时报 undefined symbol。