如何使用C++17的std::filesystem进行文件操作

在C++17标准中,<filesystem>头文件提供了一套统一且强大的文件系统接口,使得文件与目录的创建、删除、遍历、属性查询等操作变得极为简洁。本文将演示如何使用 std::filesystem 进行常见的文件操作,并给出完整的代码示例。

1. 准备工作

  • 编译器需要支持C++17,例如 GCC 8+、Clang 7+、MSVC 2017+。
  • 需要在编译时链接 stdc++fs(GCC 8之前的版本)。
g++ -std=c++17 -Wall -Wextra -O2 -pthread main.cpp -lstdc++fs

2. 常用操作

操作 关键函数 示例
创建目录 std::filesystem::create_directorycreate_directories fs::create_directories("data/logs");
删除文件 std::filesystem::remove fs::remove("temp.txt");
删除目录(含子目录) std::filesystem::remove_all fs::remove_all("data");
判断是否为文件/目录 is_regular_fileis_directory if(fs::is_regular_file(p)) { ... }
遍历目录 fs::directory_iteratorrecursive_directory_iterator for(auto& entry : fs::recursive_directory_iterator(".")) { ... }
复制文件 fs::copy fs::copy("src.txt", "dst.txt", fs::copy_options::overwrite_existing);
移动/重命名文件 fs::rename fs::rename("old.txt", "new.txt");
查询文件大小 file_size auto sz = fs::file_size("data.txt");
获取文件修改时间 last_write_time auto t = fs::last_write_time("data.txt");

3. 示例代码

下面的程序演示了从创建目录到遍历目录、复制文件、删除等完整流程。

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

namespace fs = std::filesystem;

// 打印文件或目录的基本信息
void print_info(const fs::path& p) {
    std::cout << "Path:        " << p << '\n';
    std::cout << "Is dir:      " << fs::is_directory(p) << '\n';
    std::cout << "Is regular:  " << fs::is_regular_file(p) << '\n';
    std::cout << "Size:        ";
    if (fs::is_regular_file(p)) std::cout << fs::file_size(p) << " bytes\n";
    else std::cout << "N/A\n";
    auto t = fs::last_write_time(p);
    auto s = std::chrono::time_point_cast<std::chrono::system_clock::duration>(t - fs::file_time_type::clock::now() + std::chrono::system_clock::now());
    std::cout << "Modified:    " << std::put_time(std::localtime(&std::chrono::system_clock::to_time_t(s)), "%F %T") << "\n";
    std::cout << "---------------------------------\n";
}

int main() {
    // 1. 创建目录
    fs::create_directories("demo/logs");
    std::cout << "创建目录完成。\n";

    // 2. 写一个测试文件
    std::ofstream("demo/test.txt") << "Hello, filesystem!\n";
    std::cout << "写文件完成。\n";

    // 3. 复制文件
    fs::copy("demo/test.txt", "demo/logs/test_copy.txt", fs::copy_options::overwrite_existing);
    std::cout << "文件复制完成。\n";

    // 4. 遍历 demo 目录
    std::cout << "遍历 demo 目录:\n";
    for (auto& entry : fs::recursive_directory_iterator("demo")) {
        print_info(entry.path());
    }

    // 5. 重命名文件
    fs::rename("demo/logs/test_copy.txt", "demo/logs/test_renamed.txt");
    std::cout << "文件重命名完成。\n";

    // 6. 删除单个文件
    fs::remove("demo/test.txt");
    std::cout << "删除 test.txt 完成。\n";

    // 7. 删除整个 demo 目录
    fs::remove_all("demo");
    std::cout << "删除 demo 目录完成。\n";

    return 0;
}

4. 小技巧

  • 错误处理std::filesystem 的大部分函数会抛出 std::filesystem::filesystem_error。使用 try/catch 或者 error_code 参数可以优雅地处理异常。
  • 跨平台std::filesystem 兼容 Windows、Linux、macOS。注意 Windows 需要使用 \\ 或者 R"(path)" 原始字符串。
  • 性能:对于大文件目录遍历,建议使用 fs::directory_options::skip_permission_denied 来跳过无权限的路径,以避免阻塞。

5. 结语

C++17 的 `

` 标准化了文件系统操作,减少了平台差异和繁琐的系统调用。掌握它后,你可以在 C++ 项目中更专注于业务逻辑,而不必为文件操作的细节头疼。祝你编码愉快!

发表评论