C++17 filesystem是否存在与Win32 API MoveFileEx()等价的接口?
适配方案说明
核心结论
不需要组合copy与remove_all实现,优先使用std::experimental::filesystem提供的rename接口即可,它和MoveFileEx的核心功能等价,仅特殊标志位需要额外处理。
接口适配细节
你使用的MSVC v141(对应Visual Studio 2017)自带的std::experimental::filesystem已经实现了rename接口,其Windows平台底层本身就是基于MoveFile系列API封装,天然支持同卷/跨卷移动文件、移动目录等核心能力,和你原有代码的核心逻辑对齐。
差异处理(针对MOVEFILE_WRITE_THROUGH标志)
你原有代码传入的MOVEFILE_WRITE_THROUGH标志要求操作完成前必须把数据刷入持久化存储,标准库rename默认不带这个强制保证,可根据业务需求二选一处理:
- 若业务不需要严格的掉电持久化保证:直接用标准库
rename即可,同时可以直接支持非Windows平台,不需要额外的兼容性提示。 - 若必须完全对齐原有
MOVEFILE_WRITE_THROUGH的行为:可以保留Windows分支的原有实现,非Windows分支用标准库rename即可,非Windows平台如果需要同等持久化保证,可在调用rename后追加父目录同步逻辑。
示例适配代码
#include <experimental/filesystem> namespace fs = std::experimental::filesystem; bool project::filesystem::FileSystem::rename(const std::string& oldFileName, const std::string& newFileName) { #if defined(_WIN32) || defined(WIN32) // 保留原实现保证MOVEFILE_WRITE_THROUGH行为 BOOL res = ::MoveFileEx(nativePath(oldFileName, false).c_str(), nativePath(newFileName, false).c_str(), MOVEFILE_WRITE_THROUGH); return res != FALSE; #else std::error_code ec; fs::rename(fs::path(oldFileName), fs::path(newFileName), ec); return !ec; #endif }
不推荐使用copy+remove_all的原因
- 原子性问题:复制过程中如果程序崩溃、断电,会出现新旧路径同时存在不完整文件的问题,
rename是原子操作不会出现该问题 - 性能损耗:同卷移动时
rename是元数据修改操作,耗时O(1),复制再删除需要全量读写文件,大文件场景性能差距极大 - 元数据丢失:手动复制容易丢失文件权限、创建时间、硬链接等元数据信息,标准库
rename会完整保留所有元数据
内容的提问来源于stack exchange,提问作者rbaleksandar
相关产品推荐
相关产品推荐

