在现代C++(自C++17起)中,std::filesystem 提供了一套高层次且跨平台的文件系统操作接口。它封装了底层的POSIX、Windows API,并提供了统一的语义,使得文件遍历、属性查询、路径操作等变得异常简单。下面给出一个完整的示例,演示如何:
- 递归遍历指定目录
- 过滤特定文件类型
- 获取文件大小与修改时间
- 异常安全的错误处理
#include <iostream>
#include <filesystem>
#include <chrono>
#include <iomanip>
namespace fs = std::filesystem;
// 格式化时间戳为可读字符串
std::string format_time(const fs::file_time_type& ftime) {
auto sctp = std::chrono::time_point_cast<std::chrono::system_clock::duration>(
ftime - fs::file_time_type::clock::now()
+ std::chrono::system_clock::now());
std::time_t tt = std::chrono::system_clock::to_time_t(sctp);
std::tm tm = *std::localtime(&tt);
char buffer[64];
std::strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", &tm);
return std::string(buffer);
}
// 递归遍历,收集符合条件的文件信息
void traverse(const fs::path& dir, const std::string& ext_filter = "") {
if (!fs::exists(dir) || !fs::is_directory(dir)) {
std::cerr << "路径不存在或不是目录: " << dir << '\n';
return;
}
std::cout << "遍历目录: " << dir << "\n\n";
for (auto const& entry : fs::recursive_directory_iterator(dir)) {
try {
if (entry.is_regular_file()) {
const auto& p = entry.path();
if (!ext_filter.empty() && p.extension() != ext_filter)
continue; // 过滤后缀
auto fsize = fs::file_size(p);
auto ftime = fs::last_write_time(p);
std::cout << std::left << std::setw(30) << p.string() << std::right << std::setw(10) << fsize << " bytes" << " | 修改时间: " << format_time(ftime) << '\n';
}
} catch (const std::exception& e) {
std::cerr << "读取文件信息失败: " << entry.path() << ",错误: " << e.what() << '\n';
}
}
}
int main() {
std::string target_dir;
std::cout << "请输入要遍历的目录路径: ";
std::getline(std::cin, target_dir);
std::string ext;
std::cout << "输入想要过滤的文件后缀(可空,如 .cpp),或直接回车查看全部: ";
std::getline(std::cin, ext);
try {
traverse(fs::path(target_dir), ext);
} catch (const std::exception& e) {
std::cerr << "遍历过程中发生未捕获异常: " << e.what() << '\n';
}
return 0;
}
关键点解析
| 主题 | 说明 |
|---|---|
std::filesystem 头文件 |
只需包含 ` |
| `,C++17 标准库即支持。 | |
路径对象 (fs::path) |
该类型可跨平台使用 \\ 与 /,并支持诸如 string(), filename(), parent_path() 等成员。 |
递归遍历 (recursive_directory_iterator) |
自动处理子目录,且提供 is_directory(), is_regular_file() 等检测。 |
| 异常安全 | fs::recursive_directory_iterator 在遇到错误时会抛出 std::filesystem::filesystem_error,在循环内部可以捕获并继续处理。 |
| 文件属性 | file_size(), last_write_time() 等成员函数提供常见信息。 |
| 时间格式化 | 由于 last_write_time() 返回的是 file_time_type,需要通过 chrono 转换为 time_t 再格式化。 |
适用场景
- 构建工具:如自定义
make,需要扫描源码文件。 - 文件同步:比较目录树差异。
- 日志/报告生成:列出某目录下所有文件的大小和修改时间。
- 安全扫描:找出未授权文件或旧文件。
通过上述示例,你可以快速上手 std::filesystem 并在自己的项目中加入高效、可维护的文件系统操作。祝编码愉快!