硬链接跨平台实现需区分系统约束:linux限同文件系统普通文件,windows需ntfs卷、管理员权限且不支持目录;推荐用c++17的std::filesystem::create_hard_link自动处理差异,手动封装时windows须先adjusttokenprivileges启用权限。

硬链接在 Windows 和 Linux 上根本不是一回事
Linux 的 link() 和 Windows 的 CreateHardLink() 表面相似,实则约束完全不同:Linux 硬链接只能指向同一文件系统内的普通文件,不能跨分区、不能指向目录;Windows 要求目标必须是 NTFS 卷,且仅支持文件(同样不支持目录),还强制要求调用进程有 SE_CREATE_HARD_LINK_NAME 权限(通常需管理员或显式提权)。跨平台封装时若只做“函数名映射”,大概率在 Windows 上静默失败或报错 ERROR_PRIVILEGE_NOT_HELD。
用 std::filesystem::create_hard_link 是最稳妥的起点
C++17 引入的 std::filesystem::create_hard_link 已内部处理平台差异,它在 Linux 调用 link(),在 Windows 尝试 CreateHardLinkW() 并自动处理权限检查和错误码转换。但要注意三点:
- 必须确保编译器启用 C++17(如 GCC 加
-std=c++17,MSVC 用/std:c++17) - 目标路径(existing_path)必须已存在且为常规文件;源路径(new_path)不能已存在
- Windows 下若当前用户无硬链接权限,该函数会抛出
std::filesystem::filesystem_error,.code().value()通常是5(ERROR_ACCESS_DENIED)或1314(ERROR_PRIVILEGE_NOT_HELD)
示例:
try {
std::filesystem::create_hard_link("data.bin", "backup.bin");
} catch (const std::filesystem::filesystem_error& e) {
// 检查 e.code().value() 判断是权限问题还是路径不存在
}
手动封装时,Windows 必须提前申请权限
如果不用 std::filesystem(比如需支持旧标准),Windows 侧不能直接调 CreateHardLink() 就完事。得先用 AdjustTokenPrivileges() 启用当前进程的硬链接权限,否则必败。这步在 Linux 完全不需要,强行加会编译不过。
立即学习“C++免费学习笔记(深入)”;
- Linux 侧:直接调
link(existing_path.c_str(), new_path.c_str()),返回 -1 则查errno(常见EPERM表示跨文件系统,EACCES表示权限不足) - Windows 侧:先调
OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken),再调LookupPrivilegeValue(NULL, SE_CREATE_HARD_LINK_NAME, &luid),最后AdjustTokenPrivileges()启用;之后才可安全调CreateHardLinkW() - 权限调整是一次性操作,只需在进程启动后做一次,不必每次创建都重复
硬链接不是“跨平台通用替代方案”,得先确认是否真需要它
很多场景下开发者想用硬链接是为了“零拷贝共享数据”,但实际落地时容易忽略限制:macOS 不支持硬链接到文件(只支持符号链接),容器环境(如 Docker)挂载卷后常导致跨文件系统,Windows Subsystem for Linux(WSL)里从 Windows 侧创建的硬链接在 Linux 侧不可见。如果只是想避免复制大文件,std::filesystem::copy_file(..., std::filesystem::copy_options::skip_existing) 或内存映射(mmap/CreateFileMapping)反而更可控。
真正要跨平台用硬链接,得接受它只在“原生 NTFS + 原生 ext4/xfs”这种干净环境下才稳定,其他情况建议降级为符号链接或明确报错提示用户。










