C#创建硬链接 C#如何为文件创建Hard Link

3次阅读

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

C#创建硬链接 C#如何为文件创建Hard Link

硬链接在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_DEVICEERROR_INVALID_PARAMETER

try {     File.CreateHardLink(@"C:datalink.txt", @"C:dataoriginal.txt"); } catch (UnauthorizedAccessException) {     // 缺少 SeCreateHardLinkPrivilege 或非管理员 } catch (IOException ex) when (ex.HResult == unchecked((int)0x80070011)) {     // ERROR_NOT_SAME_DEVICE:跨卷了 }
  • 第一个参数是新硬链接的路径(将被创建),第二个是已有文件的路径
  • 如果目标路径已存在,会抛出 IOException(HResult 0x80070050
  • 不支持相对路径中的 .. 跨目录解析——建议传入绝对路径并提前 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:datalink.txt", @"C:dataoriginal.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.GetCreationTimeFile.GetLastWriteTime 对所有硬链接都相同;但 File.GetLastAccessTime 是独立更新的
  • 不能用 File.Move 重命名硬链接——那只是改一个路径名,不影响其他链接;但 File.delete 删除的是链接本身,不是数据
  • 第三方工具如 fsutil hardlink list C:dataoriginal.txt 可查看某文件的所有硬链接路径

真正容易被忽略的是:硬链接无法跨越卷,也无法指向目录,且.NET的 File.Exists 对硬链接返回 true,但它不告诉你这是不是“原始”路径——你永远无法从一个路径反推出它是硬链接还是原路径。

text=ZqhQzanResources