std::filesystem::rename()是唯一标准重命名/移动接口,跨设备时抛exdev错误需降级为copy_file+remove,路径须用fs::path构造并检查权限与存在性。

std::filesystem::rename() 是唯一标准接口
直接用 std::filesystem::rename(),它不区分“重命名”和“移动”——路径变了就是移动,文件名变了就是重命名,路径+文件名都变就是跨目录重命名。没有单独的 move() 函数。
常见错误是以为它能跨设备移动大文件:实际在 Linux 或 macOS 上,如果源和目标不在同一挂载点,rename() 会抛出 std::filesystem::filesystem_error,错误码通常是 EXDEV(设备跨域)。Windows 下类似,NTFS 卷之间也可能失败。
- 成功时原子完成,无中间状态
- 目标已存在时默认失败(除非目标为空目录且源是目录)
- 不支持覆盖已有非空文件;想覆盖得先
remove()目标
跨设备移动必须手动复制+删除
检测到 EXDEV 后,不能硬 retry,得降级为“复制 + 删除”。但要注意顺序和异常安全:
- 先
copy_file(src, dst, copy_options::overwrite_existing),确保复制完成 - 再
remove(src);若这步失败,至少原文件还在,不会丢数据 - 别用
copy()(带目录递归),它对单文件行为不明确,应选copy_file()
示例关键逻辑:
yuanfang-skills 的共享设计系统,提供 token CSS 变量、12+ 主题以及可复用的布局类型 HTML 块,供 yuanfang-html-image(以及 fu...)使用。
try {
fs::rename(src, dst);
} catch (const fs::filesystem_error& e) {
if (e.code().value() == EXDEV) {
fs::copy_file(src, dst, fs::copy_options::overwrite_existing);
fs::remove(src);
} else {
throw;
}
}
路径参数必须是 fs::path 类型,别传裸字符串
虽然 rename() 接受 const path&,但传 const char* 或 std::string 会隐式构造 fs::path,看似省事,实则埋雷:
- Windows 下反斜杠
"C:\data\file.txt"会被当转义序列解析,变成非法路径 - 拼接路径时用
/操作符比字符串拼接安全:p / "sub" / "file.txt"自动适配平台分隔符 - 检查路径有效性:调用前建议先
exists(src)和!exists(dst)(除非你明确要覆盖)
错误写法:rename("a/b.txt", "c/d.txt");推荐写法:fs::rename(fs::path{"a"} / "b.txt", fs::path{"c"} / "d.txt")
rename() 对目录同样适用,但有约束
移动或重命名整个目录也用 rename(),但注意两点:
- 目标路径不能是源路径的子路径,否则行为未定义(比如把
dir重命名为dir/sub/dir) - 目标目录若已存在,必须为空,且源必须是目录;否则抛异常
- 移动目录时,其所有内容(含隐藏文件、子目录)自动迁移,无需递归操作
最容易被忽略的是权限问题:目标父目录必须有写权限,否则即使路径合法也会失败,错误信息里往往只报 Permission denied,不提示具体缺哪个权限。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










