C++17中用std::filesystem::recursive_directory_iterator遍历累加文件大小需捕获filesystem_error异常,过滤普通文件并用uintmax_t累加,避免溢出和崩溃。

用 std::filesystem::recursive_directory_iterator 遍历并累加文件大小
这是 C++17 起最直接、跨平台的方式。它自动处理符号链接(默认跳过)、权限拒绝路径(抛异常)和递归进入子目录,无需手动维护栈或队列。
关键点在于:必须捕获 std::filesystem::filesystem_error,否则遇到无权限目录(如 /proc 下某些项)或损坏的符号链接时程序会崩溃。
- 使用
std::filesystem::is_regular_file()过滤掉目录、socket、设备文件等非普通文件 - 调用
std::filesystem::file_size()获取单个文件大小,它返回uintmax_t,能覆盖大文件(如 >4GB) - 对每个合法文件做累加,用
uintmax_t或uint64_t存总和,避免int溢出
std::filesystem::directory_iterator
- 若你明确要跳过所有符号链接,构造时传
std::filesystem::directory_options::skip_permission_denied - 若想统计符号链接本身大小(而非目标),需额外判断
entry.is_symlink()并用std::filesystem::symlink_status()
Windows 上要注意 \? 前缀与长路径
Windows 默认路径长度限制为 260 字符,超过会触发 filesystem_error,错误码为 ERROR_FILENAME_EXCED_RANGE。此时需启用长路径支持,并在路径前加 \? 前缀(仅 Windows 有效)。
- 确保系统启用组策略“启用 Win32 长路径”(
ComputerWindows SettingsLocal PoliciesSecurity Options) - 代码中对 Windows 路径预处理:
std::string wide_path = "\\?\" + path.string();,再转为std::filesystem::path - 注意:
recursive_directory_iterator对\\?\路径完全兼容,但部分旧版 MSVC 工具链可能要求链接Shlwapi.lib
性能瓶颈往往不在迭代器,而在 file_size() 系统调用
每次 file_size() 都是一次 stat()(Linux/macOS)或 GetFileAttributesEx()(Windows)系统调用。对海量小文件(如日志目录下数万 .log),这会成为 I/O 瓶颈。
- 可考虑先用
entry.file_size()(C++20 引入),它复用迭代器已获取的元数据,避免重复系统调用 - 若用 C++17,只能接受开销;或改用平台 API 批量获取(如 Linux 的
getdents64+statx,但失去可移植性) - 磁盘缓存会影响实测速度——首次运行慢,后续快;SSD 上差异更小,HDD 上尤其明显
实际项目里,如果只是偶尔统计、且目录层级不深,recursive_directory_iterator 加 file_size() 就够用。真有性能敏感场景,得先确认是 CPU、I/O 还是系统调用次数卡住,再决定是否换方案。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










