硬链接在windows上仅限ntfs卷且需管理员权限,不可跨卷或指向目录;.net 5+推荐用file.createhardlink,旧版需p/invoke调用createhardlink。

硬链接在Windows上只能用于NTFS卷且需管理员权限
Windows的硬链接(Hard Link)不是跨卷的符号链接,它让多个路径指向同一个文件数据块。但C#标准库不直接提供创建硬链接的API,必须调用Win32 CreateHardLink 函数,且调用进程需有 SeCreateHardLinkPrivilege 权限——这通常意味着以管理员身份运行,或手动为用户账户启用该特权(极不推荐生产环境这么做)。
- 目标文件必须已存在,且不能是目录(
CreateHardLink不支持目录硬链接) - 源路径和目标路径必须在同一个NTFS卷上,否则返回错误
ERROR_NOT_SAME_DEVICE - .NET 5+ 的
File.CreateHardLink是封装好的托管方法,但仍底层调用CreateHardLink,权限和卷限制完全一致
使用 File.CreateHardLink(.NET 5+ 推荐)
这是最简洁、安全的方式,无需 P/Invoke,但仅适用于 .NET 5 及以上版本。它会自动处理错误码并抛出对应异常,比如 UnauthorizedAccessException 表示权限不足,IOException 可能包含 ERROR_NOT_SAME_DEVICE 或 ERROR_INVALID_PARAMETER。
try
{
File.CreateHardLink(@"C:\data\link.txt", @"C:\data\original.txt");
}
catch (UnauthorizedAccessException)
{
// 缺少 SeCreateHardLinkPrivilege 或非管理员
}
catch (IOException ex) when (ex.HResult == unchecked((int)0x80070011))
{
// ERROR_NOT_SAME_DEVICE:跨卷了
}
- 第一个参数是新硬链接的路径(将被创建),第二个是已有文件的路径
- 如果目标路径已存在,会抛出
IOException(HResult0x80070050) - 不支持相对路径中的
..跨目录解析——建议传入绝对路径并提前Path.GetFullPath
P/Invoke 调用 CreateHardLink(兼容旧版.NET Framework)
若仍在用 .NET Framework 4.8 或更早版本,需手动导入 CreateHardLink。注意字符串编码必须为Unicode(CharSet = CharSet.Unicode),且函数返回 bool,失败时应检查 Marshal.GetLastWin32Error()。
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern bool CreateHardLink(string lpFileName, string lpExistingFileName, IntPtr lpSecurityAttributes);
// 使用示例:
var success = CreateHardLink(@"C:\data\link.txt", @"C:\data\original.txt", IntPtr.Zero);
if (!success)
{
int error = Marshal.GetLastWin32Error();
// 处理 error,如 5(拒绝访问)、17(设备不同)、123(路径无效)等
}
-
lpSecurityAttributes必须传IntPtr.Zero;Windows 不支持为硬链接设置安全描述符 - 不要忽略
SetLastError = true,否则GetLastWin32Error返回值不可靠 - 某些杀软或OneDrive实时保护可能拦截硬链接创建,表现为静默失败或权限错误
硬链接 vs 符号链接 vs 副本:别混淆用途
硬链接不是快捷方式,也不是复制。它共享同一份inode(MFT记录),因此:
- 修改任一硬链接的内容,所有链接都看到变化;删除其中一个,其余仍可访问数据(直到最后一个被删)
-
File.GetCreationTime和File.GetLastWriteTime对所有硬链接都相同;但File.GetLastAccessTime是独立更新的 - 不能用
File.Move重命名硬链接——那只是改一个路径名,不影响其他链接;但File.Delete删除的是链接本身,不是数据 - 第三方工具如
fsutil hardlink list C:\data\original.txt可查看某文件的所有硬链接路径
真正容易被忽略的是:硬链接无法跨越卷,也无法指向目录,且.NET的 File.Exists 对硬链接返回 true,但它不告诉你这是不是“原始”路径——你永远无法从一个路径反推出它是硬链接还是原路径。










