
直接说结论:std::filesystem::copy 能复制文件和目录,但行为高度依赖 copy_options 参数组合,不加选项默认只复制单个文件(不递归、不覆盖、不创建父目录),多数人第一次用都会失败。
为什么 std::filesystem::copy 复制目录时没反应?
因为默认行为不递归 —— 它把目录当普通文件处理,遇到目录就抛出 std::filesystem::filesystem_error,错误信息通常是 "Is a directory" 或 "Operation not supported"。
- 必须显式传入
std::filesystem::copy_options::recursive才能进入子目录 - 若目标目录已存在,还需
std::filesystem::copy_options::skip_existing或std::filesystem::copy_options::overwrite_existing,否则会因路径冲突失败 - 目标父目录不存在时,
copy不自动创建,得提前调用std::filesystem::create_directories
复制单个文件的最小安全写法
避免覆盖误操作,同时确保目标路径可写:
namespace fs = std::filesystem;
try {
fs::copy("src.txt", "dst.txt",
fs::copy_options::skip_existing);
} catch (const fs::filesystem_error& e) {
// 处理权限不足、只读文件、目标在只读文件系统等
std::cerr << "Copy failed: " << e.what() << '\n';
}
-
skip_existing比overwrite_existing更安全,尤其对生产脚本 - 不加任何选项时,若
dst.txt已存在,会直接抛异常"File exists" - 源路径必须是普通文件;若是符号链接,默认会解引用(即复制目标文件),如需复制链接本身,加
copy_options::copy_symlinks
完整复制目录(含子目录与文件)
这是最常出错的场景:既要递归,又要处理目标存在性、又要建父目录:
立即学习“C++免费学习笔记(深入)”;
namespace fs = std::filesystem;
fs::path src = "my_folder";
fs::path dst = "backup/my_folder";
// 1. 确保目标父目录存在
fs::create_directories(dst.parent_path());
// 2. 复制(递归 + 覆盖已存在项)
try {
fs::copy(src, dst,
fs::copy_options::recursive |
fs::copy_options::overwrite_existing);
} catch (const fs::filesystem_error& e) {
std::cerr << "Directory copy failed: " << e.what() << '\n';
}
- 不能只靠
recursive—— 如果backup/不存在,copy会失败,不会自动创建backup -
overwrite_existing和skip_existing互斥,不能同时设 - 若源目录含符号链接,默认仍解引用;要保留链接结构,额外或上
copy_symlinks - Windows 下注意长路径限制(
\\?\前缀不被std::filesystem自动处理,需自行转换)
性能与跨平台差异提醒
std::filesystem::copy 是同步阻塞调用,大文件或深层目录会卡住线程;且各标准库实现行为略有不同:
- libstdc++(GCC)在 Linux 上实际调用
copy_file_range或sendfile,小文件也走 read/write - MSVC STL 在 Windows 上用
CopyFileExW,支持进度回调(但 C++ 标准接口不暴露) - macOS 的 libc++ 使用
copyfile(3),对 ACL 和扩展属性支持更完整 - 所有实现都不保证原子性:复制中途崩溃,可能留下部分文件,无回滚机制
真正需要健壮备份逻辑时,别只靠一层 copy —— 检查磁盘空间、预扫描大小、分块复制、校验哈希,这些都得自己补。










