如何使用 std::filesystem 进行跨平台文件操作?

在 C++17 标准中, 库被正式引入,提供了一套统一、跨平台的文件系统操作接口。相比传统的 POSIX 或 Windows API,std::filesystem 的语义更清晰、错误处理更方便。下面我们以一个简单的文件遍历与复制示例来演示其使用方法。

1. 环境准备

# 编译示例(假设使用 g++)
g++ -std=c++17 -Wall -Wextra -O2 -pthread main.cpp -o fs_demo

注意:部分旧编译器(如 GCC 7.x)需要加上 -lstdc++fs 链接库,现代编译器(如 GCC 9+、Clang 10+)已默认开启。

2. 基础 API

函数 说明 备注
std::filesystem::exists(const path&) 判断路径是否存在 返回 true/false
std::filesystem::is_directory(const path&) 判断是否为目录
std::filesystem::create_directories(const path&) 创建多级目录
std::filesystem::copy(const path&, const path&, copy_options) 复制文件/目录 copy_options 可自定义行为
std::filesystem::directory_iterator / recursive_directory_iterator 遍历目录 前者一次级别,后者递归

3. 代码实例

#include <iostream>
#include <filesystem>
#include <system_error>

namespace fs = std::filesystem;

int main(int argc, char* argv[]) {
    if (argc != 3) {
        std::cerr << "Usage: fs_demo <source_dir> <dest_dir>\n";
        return 1;
    }

    fs::path src(argv[1]);
    fs::path dst(argv[2]);

    // 1. 验证源目录
    if (!fs::exists(src) || !fs::is_directory(src)) {
        std::cerr << "Source directory does not exist or is not a directory.\n";
        return 1;
    }

    // 2. 创建目标目录(若不存在)
    std::error_code ec;
    fs::create_directories(dst, ec);
    if (ec) {
        std::cerr << "Failed to create destination: " << ec.message() << '\n';
        return 1;
    }

    // 3. 递归复制
    for (const auto& entry : fs::recursive_directory_iterator(src)) {
        const auto& path = entry.path();
        auto relative = fs::relative(path, src);
        auto target   = dst / relative;

        if (entry.is_directory()) {
            fs::create_directories(target, ec);
            if (ec) {
                std::cerr << "Error creating directory " << target << ": " << ec.message() << '\n';
                continue;
            }
        } else if (entry.is_regular_file()) {
            fs::copy(path, target, fs::copy_options::overwrite_existing, ec);
            if (ec) {
                std::cerr << "Error copying file " << path << " to " << target << ": " << ec.message() << '\n';
                continue;
            }
        }
    }

    std::cout << "Copy completed successfully.\n";
    return 0;
}

关键点说明

  1. 错误处理

    • 使用 std::error_code 捕获非异常错误。std::filesystem 也支持抛出 std::filesystem::filesystem_error,但显式捕获 error_code 更可控。
  2. 相对路径

    • fs::relative(path, src) 用来计算目标目录下相对路径,保证复制结构保持一致。
  3. 复制选项

    • fs::copy_options::overwrite_existing 表示目标文件已存在时覆盖。其他选项如 skip_existingupdate_existing 等可根据需求使用。
  4. 递归遍历

    • recursive_directory_iterator 会自动进入子目录并遍历所有文件和子文件夹。若只需要一次级别,可改用 directory_iterator

4. 常见错误与排查

错误 原因 解决方案
fs::relative 抛异常 源路径不在目标树上 确认 srcdst 的关系
复制时出现 Permission denied 权限不足 以管理员或 root 权限运行,或修改文件权限
目标路径为空 传递错误参数 检查命令行输入

5. 进一步阅读

  • C++20 版本的 ` ` 支持 `std::filesystem::file_time_type` 的高精度时间戳。
  • 结合 std::filesystem::file_statusfs::file_type 可实现更细粒度的文件属性检查。
  • 在大型项目中,可封装一个 FileManager 类,统一处理错误、日志、异步复制等需求。

使用 std::filesystem,你就可以用几行现代 C++ 代码完成复杂的文件操作,既安全又高效。祝编码愉快!

发表评论