std::filesystem::copy_file默认不保留源文件权限,因目标权限由umask和open默认mode(0666)决定,完全忽略st_mode;需显式使用preserve_permissions选项才可保留基础权限位。

直接说结论: std::filesystem::copy_file 默认不保留源文件权限(尤其在 Linux/macOS),且不支持“快速复制”(即底层零拷贝或 reflink),它本质是读-写循环,性能取决于 I/O 路径;想保留权限必须显式传 std::filesystem::copy_options::skip_permissions 以外的选项,但注意该函数不处理 ACL 或扩展属性。
为什么 copy_file 复制后 chmod 变了?
这是最常踩的坑:默认调用 std::filesystem::copy_file(src, dst) 等价于 copy_file(src, dst, std::filesystem::copy_options::none) —— 此时目标文件权限由当前 umask 和 open() 的默认 mode(通常是 0666)决定,**完全忽略源文件的 st_mode**。
- Linux/macOS 下:即使源是
0755,dst 很可能变成0644(被 umask 截断) - Windows 下影响较小(权限模型不同),但仍不继承 DACL
- 正确做法是加上
std::filesystem::copy_options::copy_symlinks | std::filesystem::copy_options::skip_stat_errors并**显式指定std::filesystem::copy_options::overwrite_existing(如果需要)**,但关键权限控制靠的是:std::filesystem::copy_options::preserve_permissions
如何真正保留权限(包括可执行位)?
必须使用 std::filesystem::copy_options::preserve_permissions,但它只作用于基础权限位(S_IRWXU/S_IRWXG/S_IRWXO),不复制所有权、ACL、xattr。注意它和 skip_permissions 互斥——后者会跳过权限检查,但不设权限。
- 推荐组合:
std::filesystem::copy_file(src, dst, std::filesystem::copy_options::overwrite_existing | std::filesystem::copy_options::preserve_permissions) - 若 dst 已存在且是目录,会抛
std::filesystem::filesystem_error(错误码is_a_directory),需提前判断 - 某些旧版 libstdc++(GCC preserve_permissions,建议用
stat()/chmod()手动补全
它到底快不快?有没有“快速路径”?
没有。C++20 标准未要求 copy_file 使用 copy_file_range(Linux)、fcopyfile(macOS)或 CopyFileEx(Windows)等系统级零拷贝接口。所有主流实现(libstdc++、libc++、MSVC STL)都走 read()/write() 循环,缓冲区大小通常为 8KB–64KB,无法绕过用户态内存拷贝。
立即学习“C++免费学习笔记(深入)”;
- 大文件(>100MB)时,实测比 shell
cp慢 10%–30%,主因是缺乏内核 bypass 和 mmap 优化 - 若需真正快速,Linux 下可用
copy_file_range()syscall 封装;Windows 下用CopyFileEx()并设COPY_FILE_NO_BUFFERING -
std::filesystem::copy()更慢——它会递归处理目录,且对每个文件重复 open/stat
权限不是“附带效果”,而是显式开关;性能不是“默认优化”,而是默认朴素。别依赖 copy_file 做部署或备份的关键路径,尤其当文件数多、权限敏感或体积大时——该手动 stat/chmod 就手动,该切 syscall 就切 syscall。


















