C++17起推荐用std::filesystem::recursive_directory_iterator遍历目录累加文件大小,需用is_regular_file()过滤并配合error_code避免异常;注意权限、符号链接循环及虚拟文件系统不支持file_size等问题。

用 std::filesystem::recursive_directory_iterator 遍历目录并累加文件大小
这是 C++17 起最标准、跨平台(Windows/macOS/Linux)的方案,无需调用系统 API 或第三方库。关键在于跳过目录项本身,只对 is_regular_file() 为真的条目调用 file_size()。
常见错误是直接对目录调用 file_size(),会抛出 std::filesystem::filesystem_error 异常(错误码为 not_supported 或 is_a_directory)。
- 必须捕获异常,或先用
is_regular_file()过滤 - 某些符号链接可能指向不存在的路径,建议配合
exists()和is_symlink()判断是否跳过 - 注意权限问题:遇到无读取权限的子目录时,
recursive_directory_iterator默认会抛异常;可传入std::filesystem::directory_options::skip_permission_denied选项忽略
uintmax_t get_directory_size(const std::filesystem::path& p) {
uintmax_t total = 0;
std::error_code ec;
for (const auto& entry : std::filesystem::recursive_directory_iterator(p, ec)) {
if (ec) continue; // 权限拒绝等错误,跳过
if (entry.is_regular_file(ec) && !ec) {
total += entry.file_size(ec);
}
}
return total;
}
Windows 下用 FindFirstFileExW + GetFileSizeEx 的注意事项
若项目需兼容 C++14 或禁用 ,Windows 原生 API 是可行替代。但要注意:FindFirstFileExW 返回的 WIN32_FIND_DATAW 中 nFileSizeHigh/nFileSizeLow 仅对普通文件有效,对目录恒为 0 —— 不能靠这个判断是否是文件。
- 必须用
dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY显式判断是否为目录,再决定是否递归 -
GetFileSizeEx接收的是打开的句柄,不是路径;需先用CreateFileW打开文件(记得设FILE_FLAG_BACKUP_SEMANTICS支持目录句柄,但此处只用于文件) - 32 位程序中
DWORD不足以表示 >4GB 文件,务必用LARGE_INTEGER+GetFileSizeEx
std::filesystem::file_size 报错 operation_not_permitted 怎么办
这不是权限不足,而是目标路径类型不支持获取大小 —— 最常见于:挂载的网络盘(如某些 SMB 共享)、/proc 或 /sys 下的虚拟文件、FUSE 文件系统中的特殊节点。此时 file_size() 会失败,但 exists() 可能仍返回 true。
立即学习“C++免费学习笔记(深入)”;
- 不要假设所有
is_regular_file()为 true 的路径都能成功调用file_size() - 始终用
std::error_code重载版本,并检查ec.value() != 0,而非依赖异常 - 对失败项可记录警告并跳过,避免整个统计中断
大目录下性能差异:预分配 vs 流式遍历
递归遍历本身开销不大,瓶颈往往在频繁的系统调用和磁盘 I/O。实测发现:recursive_directory_iterator 内部已做批处理优化,比手写多层 FindFirstFile 循环快 15–20%;而如果先收集全部路径再逐个 file_size(),内存占用高且无明显提速。
- 避免把所有
path存进std::vector再遍历 —— 没有并发优势,还多一次内存拷贝 - 若需并发加速,应按子目录分片(非单个文件),每个线程处理一个子树,否则 I/O 竞争反而更慢
- SSD 上差异不明显,但机械硬盘上顺序访问比随机
stat快得多,所以保持迭代器自然顺序很重要
真正容易被忽略的是符号链接循环引用 —— recursive_directory_iterator 默认不检测,可能无限递归。启用 std::filesystem::directory_options::follow_directory_symlink 时要格外小心,生产环境建议默认关闭。










