利用C++17的std::filesystem库进行跨平台文件系统操作

在C++17标准发布后,标准库新增了std::filesystem模块,为文件与目录的操作提供了统一、跨平台的接口。相比传统的POSIX或Windows API,std::filesystem不再需要手工处理路径分隔符、错误码等细节,极大简化了文件系统编程。本文将通过几个典型场景,演示如何利用该库完成常见任务,并给出一些实用技巧。


1. 基础使用

首先需要包含头文件:

#include <filesystem>
namespace fs = std::filesystem;

使用前请确保编译器支持C++17,并链接对应的标准库(如g++:-lstdc++fs 在部分版本中需要)。

1.1 创建目录

fs::create_directories("/tmp/example/subdir");

create_directories 会递归创建不存在的父目录;若目录已存在,则返回false

1.2 复制与移动

fs::copy("/tmp/source.txt", "/tmp/dest.txt", fs::copy_options::overwrite_existing);

fs::copy 默认不覆盖同名文件,可通过copy_options控制。移动同样可使用fs::renamefs::move(C++23)。

1.3 删除文件/目录

fs::remove("/tmp/old.txt");          // 仅删除文件
fs::remove_all("/tmp/old_folder");   // 递归删除目录

2. 遍历目录

使用fs::directory_iteratorfs::recursive_directory_iterator可以轻松列出文件。

for (const auto& entry : fs::recursive_directory_iterator("/tmp"))
{
    std::cout << entry.path() << '\n';
}

若只关心文件,可以过滤掉子目录:

for (const auto& entry : fs::recursive_directory_iterator("/tmp"))
{
    if (entry.is_regular_file())
        std::cout << entry.path() << '\n';
}

3. 读取文件元信息

fs::file_time_type ctime = fs::last_write_time("/tmp/example.txt");
auto s = fs::file_size("/tmp/example.txt");

last_write_time 返回的时间点可通过std::chrono转换为可读时间。


4. 路径操作

fs::path 对路径进行分割、拼接、相对化等操作。

fs::path p1("/usr");
fs::path p2("bin/g++");
fs::path full = p1 / p2;          // /usr/bin/g++

fs::path relative = full.lexically_relative("/usr"); // bin/g++

lexically_normal() 可以去除多余的...,但不访问文件系统。


5. 高级技巧

5.1 与错误码配合使用

std::error_code 可以捕获异常信息,避免抛出。

std::error_code ec;
fs::remove("/tmp/nonexistent", ec);
if (ec) std::cerr << "删除失败: " << ec.message() << '\n';

5.2 对文件进行锁定(文件锁)

虽然std::filesystem本身不支持文件锁,但可配合系统API实现。示例(Linux):

#include <fcntl.h>
int fd = open("/tmp/file.txt", O_RDWR);
flock(fd, LOCK_EX);  // 互斥锁
// 读写文件
flock(fd, LOCK_UN);
close(fd);

5.3 对大文件进行分块读取

使用std::ifstreamfs::file_size配合,可实现高效的分块读取。

std::ifstream ifs("/tmp/large.bin", std::ios::binary);
size_t size = fs::file_size(ifs);
size_t block = 1024 * 1024; // 1MB
std::vector <char> buffer(block);
while (ifs.read(buffer.data(), block))
{
    // 处理 block 字节
}

6. 性能注意

  • 对于大规模文件遍历,建议使用fs::directory_options::skip_permission_denied避免因权限问题中断。
  • fs::file_size 只对常规文件有效;对符号链接可使用symlink_status

7. 结语

std::filesystem 的出现,大大降低了 C++ 文件系统编程的门槛。它统一了平台差异、提供了异常安全的接口,并与 STL 其他组件(如std::chronostd::vector等)配合使用。掌握这一模块后,开发者可以更专注于业务逻辑,而非底层细节。祝你在项目中愉快地使用 std::filesystem,构建跨平台、可靠的文件操作功能。

发表评论