C++17起应使用std::filesystem::recursive_directory_iterator遍历所有文件,注意捕获file_size()异常、避免重复stat调用、区分逻辑大小与磁盘占用,并处理跨平台差异。

用 std::filesystem::recursive_directory_iterator 遍历所有文件
这是 C++17 起最直接的方式,不用自己手写递归逻辑,recursive_directory_iterator 会自动进入子目录。注意它默认跳过符号链接(除非显式启用),且对循环软链、权限不足的目录会抛异常,得捕获处理。
常见错误是直接用 std::filesystem::directory_iterator —— 它只遍历当前层,不会进子目录,结果明显偏小。
- 必须开启 C++17 或更高标准(如编译加
-std=c++17) - Windows 下路径分隔符用反斜杠不影响,
std::filesystem内部会标准化 - 若需跳过挂载点(如 Linux 的
/proc、/sys),得手动检查is_symlink()和is_mount_point()(C++23 才有后者,C++17 可用status().type()粗略判断)
累加文件大小时小心 file_size() 抛异常
std::filesystem::file_size() 对目录、socket、管道、无权限文件都会抛 std::filesystem::filesystem_error。不捕获就 crash,尤其在遍历系统目录时几乎必现。
别写成 size += file_size(p) 一行了事——得包 try/catch,而且 catch 后要决定是跳过、记日志,还是中断。
- 目录本身没有“大小”,
file_size()对目录行为未定义(通常抛异常),所以只对is_regular_file()为 true 的路径调用 - 某些特殊文件(如 /dev/null)可能返回 0,但不会抛异常;而 /proc/kcore 这类可能返回极大值或直接失败
- 用
uintmax_t接收file_size()返回值,避免 32 位截断(虽然少见,但大于 4GB 的单文件很常见)
性能关键:避免重复 status() 调用
每次调用 is_regular_file(p) 或 file_size(p) 都可能触发一次 stat() 系统调用。同一个路径反复查,效率很低。
正确做法是先调一次 std::filesystem::status(p),再从返回的 file_status 对象里取类型和大小(C++20 起 file_size(const std::filesystem::path&, std::error_code&) 重载支持传入缓存的 status)。
- C++17 中可这样优化:
auto s = status(p); if (is_regular_file(s)) size += file_size(p, ec);,其中ec是std::error_code&,避免异常开销 - Windows 上 NTFS 卷的硬链接会被重复统计(
file_size()返回各自大小),若需去重,得记录device_id + inode(用std::filesystem::space()不行,得用平台 API) - 不要用
std::filesystem::canonical(p)做去重——它慢,且对相对路径可能意外失败
跨平台差异:权限错误和特殊文件系统表现不同
Linux 下遇到 /proc 或 /sys 里的文件,file_size() 常返回 0 或抛异常;macOS 的 APFS 对空目录可能返回非零大小;Windows 的 NTFS 压缩文件,file_size() 返回的是逻辑大小(解压后),不是磁盘占用(即 du 显示的值)。
如果目标是“磁盘实际占用”,C++ 标准库做不到——得调用平台 API:GetCompressedFileSize(Win)、ioctl(fd, FIEMAP)(Linux)、getattrlist()(macOS)。
- 多数场景下,“逻辑大小总和”已够用,但备份工具或磁盘分析工具必须区分逻辑大小 vs 物理占用
- Windows 上用
std::filesystem遍历时,若路径含中文且控制台代码页非 UTF-8(如 GBK),可能乱码或跳过——建议程序内统一用 UTF-8 编码处理std::filesystem::path - 某些 NAS 或网络文件系统(如 SMB)会把
file_size()返回值缓存,导致刚写完的文件大小不准,需加refresh()(C++20)或绕过缓存重查
实际写的时候,最易忽略的是异常边界和跨平台语义差异——比如以为 file_size() 总是安全的,结果一跑 Linux 就崩;或者在 Windows 上测得好好的,到 macOS 上发现大小对不上。这些都不是 bug,是标准库按平台语义做的合理设计。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











