C++怎么读取目录 C++中dirent.h遍历文件夹【实战】

1次阅读

Windows 不支持 dirent.h,需用 C++17 std::filesystem::directory_iterator 替代;它跨平台、自动处理路径与编码,且无需手动管理资源。

C++ 怎么读取目录 C++ 中 dirent.h 遍历文件夹【实战】

dirent.h 在 Windows 上根本不能用

直接告诉你:Windows 默认不带 dirent.h,VS、MinGW(非 MSYS2 环境)下编译会报错 fatal error: dirent.h: No such file or directory。这不是你路径没配对,是它压根不是 Windows 原生 API 的一部分。

常见错误现象:#include <dirent.h></dirent.h> 编译失败;或用了 MinGW-w64 但忘了加 -D__USE_MINGW_ANSI_STDIO 导致 readdir() 返回乱码文件名。

  • Linux/macOS 可直接用,头文件和函数都标准
  • Windows 下想用,得自己引入兼容层(如 tronkko/dirent),或改用 <filesystem></filesystem>(C++17 起)
  • MSVC 用户别挣扎——别试图找“Windows 版 dirent.h”,那是白费时间

std::filesystem::directory_iterator 是更靠谱的跨平台选择

C++17 引入的 std::filesystem 不仅能遍历目录,还自动处理路径分隔符、编码、符号链接等脏活。它不是“替代方案”,而是当前 C++ 的事实标准。

使用场景:需要跨平台、要过滤文件类型、要获取文件大小 / 最后修改时间、不想手动管理 DIR* 生命周期。

立即学习 C++ 免费学习笔记(深入)”;

#include <filesystem> namespace fs = std::filesystem;  for (const auto& entry : fs::directory_iterator("/path/to/dir")) {if (entry.is_regular_file()) {std::cout << entry.path().filename() << "n";} }
  • 注意:GCC 需加编译选项 -lstdc++fs(GCC
  • directory_iterator 不递归,要递归请用 recursive_directory_iterator
  • 路径字符串建议用 fs::path 构造,避免裸字符串拼接导致反斜杠转义问题

readdir() 的三个关键陷阱(Linux/macOS 下真要用)

如果你明确在 Linux/macOS 上写服务、嵌入式工具,或必须对接旧代码,readdir() 还是得懂。但它比看起来危险得多。

常见错误现象:程序随机崩溃、漏读文件、中文文件名显示为 ????readdir() 返回 NULL 后继续解引用。

  • struct dirent* 指针由 readdir() 内部复用,每次调用都会覆盖前次内容,不能存指针、不能跨循环迭代保存
  • 文件名字段 d_name 是 char 数组,长度固定(NAME_MAX),超长名会被截断,且不保证以 结尾(需手动检查)
  • 返回值为 NULL 表示结束或出错,必须用 errno 判断:若 errno == 0 才是正常结束;否则可能是权限不足或 I/O 错误

性能差异:filesystem vs readdir vs system(“ls”)

别图省事用 system("ls") 解析输出——慢、不可靠、有 shell 注入风险,且无法获取文件元信息。

真实性能排序(同等条件下):readdir()std::filesystem::directory_iterator > system("ls")。前者都是系统调用直通,后者要 fork + exec + pipe + 字符串解析。

  • readdir() 最轻量,但需手动处理编码、过滤、stat
  • std::filesystem 在首次构造时可能多一次 stat()(取决于实现),但后续 entry.is_regular_file() 等操作基本零开销(缓存了 d_type 或 stat 结果)
  • 如果只想要文件名列表且不做任何判断,readdir() 确实略快,但差不了几个微秒——够不到性能瓶颈级别

事情说清了就结束。最常被忽略的是:跨平台项目里硬塞 dirent.h,结果 CI 在 Windows 上直接挂;或者以为 std::filesystem“只是语法糖”,没意识到它背后是不同 OS 的原生 API 封装,路径行为、错误码、编码处理全都不一样。

text=ZqhQzanResources