在C++17之前,遍历文件夹需要依赖操作系统提供的API,比如Windows的FindFirstFile、Linux的opendir等,这些接口不仅平台差异大,使用起来也比较繁琐。C++17正式将filesystem纳入标准库,提供了统一的目录遍历接口,大幅降低了跨平台文件操作的难度。

C++17 filesystem基础准备
使用filesystem前需要包含对应的头文件,并且注意不同编译器的命名空间差异。大部分现代编译器已经完全支持C++17的filesystem,部分旧版本编译器可能需要使用实验性的命名空间。
#include <iostream> #include <filesystem> // 对于部分旧版本编译器,可能需要使用 std::experimental::filesystem // 同时需要链接对应的库,比如GCC需要添加 -lstdc++fs 编译选项 namespace fs = std::filesystem;
基础非递归遍历文件夹
使用directory_iterator可以实现对指定目录的直接子项遍历,不会进入子目录。遍历过程中每个迭代项都是directory_entry对象,可以获取文件的相关属性。
#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;
int main() {
// 要遍历的目标文件夹路径,这里使用当前目录作为示例
fs::path target_dir = "./test_dir";
// 检查路径是否存在且是目录
if (!fs::exists(target_dir) || !fs::is_directory(target_dir)) {
std::cerr << "目标路径不存在或不是目录" << std::endl;
return 1;
}
// 使用directory_iterator遍历目录
for (const auto& entry : fs::directory_iterator(target_dir)) {
// 获取文件完整路径
fs::path file_path = entry.path();
// 判断是否是普通文件
if (fs::is_regular_file(entry.status())) {
std::cout << "普通文件: " << file_path.string() << std::endl;
} else if (fs::is_directory(entry.status())) {
std::cout << "子目录: " << file_path.string() << std::endl;
} else {
std::cout << "其他类型: " << file_path.string() << std::endl;
}
}
return 0;
}
递归遍历所有子目录文件
如果需要遍历目标目录下的所有子目录中的文件,可以使用recursive_directory_iterator,它会自动递归进入所有子目录进行遍历。
#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;
int main() {
fs::path target_dir = "./test_dir";
if (!fs::exists(target_dir) || !fs::is_directory(target_dir)) {
std::cerr << "目标路径不存在或不是目录" << std::endl;
return 1;
}
// 使用递归迭代器遍历所有子项
for (const auto& entry : fs::recursive_directory_iterator(target_dir)) {
fs::path file_path = entry.path();
// 只输出普通文件的路径
if (fs::is_regular_file(entry.status())) {
std::cout << "文件路径: " << file_path.string() << std::endl;
}
}
return 0;
}
过滤特定类型的文件
实际开发中经常需要只处理特定后缀的文件,比如只遍历所有的txt文件或者cpp文件,可以在遍历过程中添加后缀判断逻辑。
#include <iostream>
#include <filesystem>
#include <string>
namespace fs = std::filesystem;
int main() {
fs::path target_dir = "./test_dir";
std::string target_ext = ".cpp"; // 要过滤的目标后缀
if (!fs::exists(target_dir) || !fs::is_directory(target_dir)) {
std::cerr << "目标路径不存在或不是目录" << std::endl;
return 1;
}
for (const auto& entry : fs::recursive_directory_iterator(target_dir)) {
fs::path file_path = entry.path();
if (fs::is_regular_file(entry.status())) {
// 获取文件后缀并转为小写比较
std::string ext = file_path.extension().string();
// 简单处理后缀大小写问题
for (char& c : ext) {
c = tolower(c);
}
if (ext == target_ext) {
std::cout << "目标文件: " << file_path.string() << std::endl;
}
}
}
return 0;
}
遍历过程中的异常处理
遍历目录时可能会遇到权限不足、路径不存在、文件被占用等异常情况,需要使用异常处理机制保证程序的稳定性。
#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;
int main() {
fs::path target_dir = "./test_dir";
try {
if (!fs::exists(target_dir)) {
std::cerr << "路径不存在" << std::endl;
return 1;
}
for (const auto& entry : fs::directory_iterator(target_dir)) {
try {
// 尝试获取文件状态,可能触发异常
fs::file_status status = entry.status();
if (fs::is_regular_file(status)) {
std::cout << "文件: " << entry.path().string() << std::endl;
}
} catch (const fs::filesystem_error& e) {
std::cerr << "处理文件 " << entry.path().string() << " 时出错: " << e.what() << std::endl;
}
}
} catch (const fs::filesystem_error& e) {
std::cerr << "遍历目录失败: " << e.what() << std::endl;
return 1;
}
return 0;
}
两种迭代器的选择建议
directory_iterator和recursive_directory_iterator的选择需要根据实际需求决定:
- 如果只需要处理目标目录下的直接子项,不需要进入子目录,优先使用
directory_iterator,性能更高 - 如果需要处理目标目录及所有子目录下的文件,使用
recursive_directory_iterator,避免自己实现递归逻辑
另外需要注意,filesystem的路径处理是跨平台的,不需要担心Windows的反斜杠和Linux的正斜杠差异,库会自动处理路径分隔符的转换。
C++17filesystem目录遍历文件遍历修改时间:2026-07-09 09:42:29