在c++开发中,统计指定文件夹下所有文件的总数量(包含递归子目录)是经常会遇到的需求,比如需要批量处理文件、统计项目文件规模等场景都需要用到这个功能。实现这个功能的核心思路是先遍历当前目录下的所有条目,判断每个条目是文件还是目录,如果是文件就计数加一,如果是目录就递归进入该目录继续统计。

方案一:使用C++17标准库filesystem
C++17引入了filesystem标准库,提供了跨平台的目录和文件操作接口,不需要依赖系统特定的API,兼容性更好,是推荐的实现方式。
实现步骤
- 引入filesystem头文件,注意不同编译器的命名空间可能有差异,gcc和clang使用std::filesystem,msvc早期版本可能需要用std::experimental::filesystem
- 定义一个递归函数,接收目录路径作为参数,返回该目录下的文件总数
- 使用directory_iterator遍历目录下的所有条目,判断条目类型,文件则计数,目录则递归调用函数
- 处理可能的异常,比如目录不存在、没有访问权限等情况
完整代码示例
#include <iostream>
#include <filesystem>
#include <system_error>
// 递归统计目录下的文件总数,包含子目录
// path: 目标目录路径
// ec: 错误信息输出参数
uint64_t count_files_recursive(const std::filesystem::path& path, std::error_code& ec) {
uint64_t file_count = 0;
// 遍历当前目录下的所有条目
for (const auto& entry : std::filesystem::directory_iterator(path, ec)) {
if (ec) {
// 遍历出错,返回当前已统计的数量
return file_count;
}
if (std::filesystem::is_regular_file(entry.status())) {
// 是普通文件,计数加一
file_count++;
} else if (std::filesystem::is_directory(entry.status())) {
// 是目录,递归统计子目录的文件数量,累加到总计数
file_count += count_files_recursive(entry.path(), ec);
}
}
return file_count;
}
int main() {
std::string target_dir = "./test_dir"; // 目标目录路径,可替换为实际需要统计的目录
std::error_code ec;
uint64_t total_files = count_files_recursive(target_dir, ec);
if (ec) {
std::cerr << "统计文件数量失败,错误信息:" << ec.message() << std::endl;
return 1;
}
std::cout << "目标目录[" << target_dir << "]下所有文件的总数量为:" << total_files << std::endl;
return 0;
}
代码说明
上述代码中,std::filesystem::directory_iterator用于遍历目录条目,is_regular_file判断是否为普通文件,is_directory判断是否为目录。递归调用count_files_recursive函数处理子目录,最终累加得到所有文件的总数。使用std::error_code处理异常,避免程序因为目录访问错误直接崩溃。
方案二:使用Windows系统API(仅Windows平台)
如果是Windows平台下的开发,也可以使用Windows提供的文件操作API来实现,不需要依赖C++17标准库,适合老版本编译器环境。
实现步骤
- 引入Windows.h头文件,使用Windows的文件查找相关API
- 使用
FindFirstFile和FindNextFile遍历目录下的所有条目 - 过滤掉
.和..两个特殊目录条目 - 判断条目是文件还是目录,文件计数,目录递归处理
完整代码示例
#include <iostream>
#include <windows.h>
#include <tchar.h>
// 递归统计Windows目录下的文件总数,包含子目录
// dir_path: 目标目录路径,需要以*结尾,比如C:test*
uint64_t count_files_win_recursive(const TCHAR* dir_path) {
uint64_t file_count = 0;
WIN32_FIND_DATA find_data;
HANDLE h_find = FindFirstFile(dir_path, &find_data);
if (h_find == INVALID_HANDLE_VALUE) {
return 0;
}
do {
// 跳过.和..两个特殊目录
if (_tcscmp(find_data.cFileName, _T(".")) == 0 || _tcscmp(find_data.cFileName, _T("..")) == 0) {
continue;
}
// 判断是否为目录
if (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
// 拼接子目录路径,递归统计
TCHAR sub_dir[MAX_PATH];
_stprintf_s(sub_dir, _T("%s%s\*"), dir_path, find_data.cFileName);
// 去掉路径末尾的*,因为dir_path已经包含*
sub_dir[_tcslen(sub_dir) - 2] = _T(' ');
file_count += count_files_win_recursive(sub_dir);
} else {
// 是文件,计数加一
file_count++;
}
} while (FindNextFile(h_find, &find_data) != 0);
FindClose(h_find);
return file_count;
}
int main() {
const TCHAR* target_dir = _T("C:\test_dir\*"); // 目标目录路径,末尾加*匹配所有条目
uint64_t total_files = count_files_win_recursive(target_dir);
_tprintf(_T("目标目录下所有文件的总数量为:%llun"), total_files);
return 0;
}
代码说明
该方案使用Windows的FindFirstFile和FindNextFileAPI遍历目录,需要注意过滤掉.和..两个特殊目录,避免递归死循环。拼接子目录路径时要注意格式,确保递归调用时路径正确。该方案仅能在Windows平台运行,不具备跨平台特性。
两种方案对比
| 对比项 | filesystem标准库方案 | Windows API方案 |
|---|---|---|
| 跨平台性 | 支持Windows、Linux、macOS等主流平台 | 仅支持Windows平台 |
| 编译器要求 | 需要支持C++17及以上的编译器 | 无特殊要求,老版本编译器也可使用 |
| 代码复杂度 | 代码简洁,接口易用 | 代码相对繁琐,需要处理更多平台特定细节 |
| 推荐使用场景 | 新项目、跨平台项目 | 仅Windows平台的老项目,无法升级编译器的情况 |
注意事项
- 统计文件数量时,默认只统计普通文件,不包含符号链接、设备文件等特殊类型文件,如果需要统计特殊类型文件,可以调整判断条件
- 如果目录层级非常深或者文件数量非常多,递归调用可能会导致栈溢出,这种情况下可以将递归改为栈模拟的迭代实现
- 遍历目录时要注意权限问题,没有访问权限的目录会遍历失败,需要做好异常处理