如何在 C++17 中使用 std::filesystem 实现递归文件搜索?

在现代 C++ 开发中,文件系统操作常常需要遍历目录树。自 C++17 起,标准库提供了 <filesystem> 头文件,方便进行文件路径操作、文件属性查询以及目录遍历。本文将展示一个完整示例,演示如何使用 std::filesystem::recursive_directory_iterator 在指定路径下递归搜索所有文件,并输出文件路径、大小以及修改时间。


1. 环境准备

  • 编译器:支持 C++17 或更高版本,例如 g++-11、clang++-12 或 MSVC 2019(/std:c++17)
  • 依赖:无外部库,直接使用标准库
g++ -std=c++17 -Wall -Wextra -O2 recursive_search.cpp -o recursive_search

2. 代码实现

#include <iostream>
#include <filesystem>
#include <chrono>
#include <iomanip>

namespace fs = std::filesystem;

// 格式化时间戳为易读字符串
std::string format_time(fs::file_time_type ft) {
    using namespace std::chrono;
    auto sctp = time_point_cast<system_clock::duration>(ft - fs::file_time_type::clock::now()
                                                        + system_clock::now());
    std::time_t t = system_clock::to_time_t(sctp);
    std::tm tm = *std::localtime(&t);
    std::ostringstream oss;
    oss << std::put_time(&tm, "%Y-%m-%d %H:%M:%S");
    return oss.str();
}

// 递归搜索函数
void recursive_search(const fs::path& dir) {
    if (!fs::exists(dir)) {
        std::cerr << "路径不存在: " << dir << '\n';
        return;
    }
    if (!fs::is_directory(dir)) {
        std::cerr << "指定路径不是目录: " << dir << '\n';
        return;
    }

    for (const auto& entry : fs::recursive_directory_iterator(dir)) {
        try {
            if (entry.is_regular_file()) {
                auto fsize = entry.file_size();
                auto ftime = entry.last_write_time();
                std::cout << "文件: " << entry.path() << '\n' << "    大小: " << fsize << " 字节\n" << "    最后修改: " << format_time(ftime) << '\n';
            }
        } catch (const std::exception& e) {
            std::cerr << "访问文件失败: " << entry.path() << " -> " << e.what() << '\n';
        }
    }
}

int main(int argc, char* argv[]) {
    if (argc < 2) {
        std::cerr << "用法: " << argv[0] << " <目录路径>\n";
        return 1;
    }

    fs::path target_dir(argv[1]);
    recursive_search(target_dir);

    return 0;
}

3. 关键点说明

关键点 说明
std::filesystem::recursive_directory_iterator 自动递归遍历目录,轻松获取子目录和文件
entry.is_regular_file() 过滤掉符号链接、目录等非普通文件
entry.file_size() 读取文件大小,若文件被删除或无权限会抛异常
entry.last_write_time() 获取文件最后修改时间,结合 format_time 转为可读字符串
异常处理 遍历过程中可能出现权限错误或删除操作,使用 try-catch 保证程序不崩溃

4. 扩展功能

  1. 按文件后缀筛选
    if (entry.path().extension() == ".cpp") { /* 只处理 C++ 源文件 */ }
  2. 并行遍历
    使用 std::async 或第三方并发库(如 TBB)将每个子目录分配给线程,提高大目录下的扫描速度。
  3. 过滤隐藏文件
    判断 entry.path().filename().string().front() != '.' 可跳过隐藏文件(Linux / macOS)或带点前缀的文件。
  4. 统计信息
    在遍历过程中累加文件数量、总大小等,最后输出统计报告。

5. 小结

  • C++17 ` ` 让文件系统操作变得直观且类型安全。
  • recursive_directory_iterator 是实现递归搜索的核心工具。
  • 通过异常捕获与条件过滤,可以构建健壮且功能丰富的文件搜索工具。

随时将上述示例集成到你的项目中,即可快速获得跨平台的递归文件遍历功能。祝编码愉快!

发表评论