最可靠跨平台递归遍历目录的方法是使用C++17的std::filesystem::recursive_directory_iterator,需捕获filesystem_error异常、用uintmax_t处理文件大小、跳过权限不足和特殊目录,并禁用符号链接跟随以避免循环和性能损耗。

用 std::filesystem::recursive_directory_iterator 遍历目录最可靠
Windows 和 Linux 下跨平台递归遍历目录,std::filesystem 是 C++17 起的官方方案,比手写递归或调用系统命令更安全、更易控制。它自动跳过权限不足的子目录(抛异常可捕获),也支持符号链接处理策略。
关键点:
-
std::filesystem::recursive_directory_iterator默认会进入所有子目录,包括软链接指向的路径(除非传入std::filesystem::directory_options::skip_permission_denied) - 遍历时每个
std::filesystem::directory_entry可直接调用.file_size()获取大小,但注意:对目录、设备文件、管道等调用会抛std::filesystem::filesystem_error - 必须用
try/catch包裹.file_size(),否则遇到特殊文件(如/proc/kcore或挂载点)直接崩溃
判断“大文件”必须用 std::uintmax_t 避免溢出
std::filesystem::file_size() 返回类型是 std::uintmax_t(通常是 unsigned long long),不能用 int 或 size_t 接收——1GB 是 1024ULL * 1024 * 1024,约 10⁹ 级别,32 位 size_t 在某些平台可能溢出。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 阈值定义为
const std::uintmax_t threshold = 1024ULL * 1024 * 1024;,用ULL后缀确保字面量是无符号长整型 - 比较时统一用
entry.file_size() > threshold,不要先转成double或除法换算,避免浮点误差和性能损耗 - Windows 下 NTFS 卷上稀疏文件或加密文件可能返回异常大的值(如
0xFFFFFFFFFFFFFFFF),需额外过滤:if (size != static_cast<:uintmax_t>(-1))</:uintmax_t>
性能瓶颈在磁盘 I/O,不是递归逻辑本身
真正慢的是读取文件元数据(尤其是网络文件系统或大量小文件夹),recursive_directory_iterator 本身开销极小。优化方向很明确:
- 禁用符号链接跟随:构造迭代器时传
std::filesystem::directory_options::follow_directory_symlink以外的选项,避免误入循环或远程挂载点 - 跳过明显不可能超限的目录:比如
node_modules、.git、__pycache__,用iterator.pop()提前退出子树(需配合options构造) - 多线程不推荐:文件系统调用本质是阻塞 I/O,开多线程反而增加上下文切换开销;真要加速,用异步 I/O(如 Linux 的
io_uring)或并行扫描不同驱动器
常见错误:权限拒绝导致程序中断或漏扫
未处理 std::filesystem::filesystem_error 是最常踩的坑——遇到 /root 或 Docker 容器内受限路径时,迭代器构造或 ++it 会直接 throw,整个扫描就停了。
正确做法是把单次迭代包装成可恢复操作:
- 用
try { ++it; }捕获异常后继续,而不是让异常向上冒泡 - 对每个
entry单独 tryfile_size(),失败就跳过该条目,不影响后续 - Windows 上还可能遇到
ERROR_SHARING_VIOLATION(文件被占用),此时file_size()也会失败,同样应忽略
实际代码里最容易被忽略的是:即使开了 skip_permission_denied,某些文件系统(如 WSL2 的 ext4)仍可能抛异常,所以 catch 不能省。


















