C++17 引入了 std::filesystem,它提供了跨平台的文件系统操作功能。利用该库,我们可以轻松实现遍历指定目录下的所有文件、子目录,并统计它们的大小。下面给出一个完整示例,并对关键步骤进行逐行说明,帮助你快速掌握该技术。
一、准备工作
-
编译器支持
- GCC 8.1+、Clang 7.0+、MSVC 2017+ 都已支持
std::filesystem。 - 需要在编译命令中链接
stdc++fs(GCC 8.1以下)或-lstdc++fs,GCC 9.1+ 与 Clang 7.0+ 已默认链接。
- GCC 8.1+、Clang 7.0+、MSVC 2017+ 都已支持
-
包含头文件
#include <iostream> #include <filesystem> #include <iomanip> -
命名空间简写(可选)
namespace fs = std::filesystem;
二、核心代码
int main(int argc, char* argv[]) {
// 1. 解析命令行参数
if (argc != 2) {
std::cerr << "用法: " << argv[0] << " <目录路径>\n";
return 1;
}
fs::path targetDir(argv[1]);
// 2. 判断路径是否存在且为目录
if (!fs::exists(targetDir) || !fs::is_directory(targetDir)) {
std::cerr << "错误:指定路径不存在或不是目录。\n";
return 1;
}
std::uintmax_t totalSize = 0; // 累计总大小
std::size_t fileCount = 0; // 文件计数
std::size_t dirCount = 0; // 子目录计数
// 3. 递归遍历目录
for (auto const& dirEntry : fs::recursive_directory_iterator(targetDir)) {
try {
if (dirEntry.is_regular_file()) {
++fileCount;
totalSize += dirEntry.file_size(); // 文件大小(字节)
} else if (dirEntry.is_directory()) {
++dirCount;
}
} catch (const fs::filesystem_error& e) {
// 处理访问错误(权限、符号链接失效等)
std::cerr << "访问错误:" << e.what() << '\n';
}
}
// 4. 输出结果
std::cout << std::fixed << std::setprecision(2);
std::cout << "目录统计信息:\n";
std::cout << " 总文件数 :" << fileCount << '\n';
std::cout << " 子目录数 :" << dirCount << '\n';
std::cout << " 总文件大小:" << totalSize / (1024.0 * 1024.0) << " MB\n";
return 0;
}
代码要点说明
| 步骤 | 说明 |
|---|---|
| 1. 解析命令行参数 | 让程序可接受目录路径作为参数,避免硬编码。 |
| 2. 路径校验 | fs::exists 检查路径是否存在,fs::is_directory 确认为目录。 |
| 3. 递归遍历 | fs::recursive_directory_iterator 自动处理子目录;使用 is_regular_file()、is_directory() 判断类型。 |
| 4. 统计文件大小 | file_size() 返回字节数;在循环中累加。 |
| 5. 错误处理 | try-catch 捕获 filesystem_error,防止因权限或无效符号链接导致程序崩溃。 |
| 6. 输出结果 | 将总大小转换为 MB 并保留两位小数,使用 std::fixed 与 std::setprecision。 |
三、进阶功能
-
过滤文件类型
if (dirEntry.path().extension() == ".cpp") { /* 统计 .cpp 文件 */ } -
忽略符号链接
if (dirEntry.is_symlink()) continue; -
多线程并行遍历
- 使用
std::async或tbb::parallel_for_each,将目录拆分为子目录并行处理。 - 注意对
totalSize、fileCount等共享变量使用互斥锁或原子操作。
- 使用
-
展示进度条
- 通过
std::chrono记录耗时,并在std::cout中更新进度。
- 通过
四、常见问题
| 问题 | 解决办法 |
|---|---|
| 编译错误:‘filesystem’ 未定义 | 确认使用的编译器版本并开启 C++17 标准 (-std=c++17)。 |
| 运行时出现 Permission denied | 检查目录权限,或使用 fs::status 判断是否可读。 |
| 统计结果异常大 | 确认是否对同一文件统计多次,可能因符号链接导致。 |
五、总结
std::filesystem极大简化了文件系统操作,提供了安全、跨平台的 API。- 通过递归迭代器,可轻松实现目录遍历与文件统计。
- 在实际项目中,可进一步扩展功能,如按文件类型分组、按时间戳筛选、并行处理等,以满足更复杂的需求。
掌握这些基础后,你就能在 C++ 项目中高效地处理文件系统任务,为后续的日志分析、资源管理等功能打下坚实基础。