NTFS文件系统的硬链接是同一个文件数据块的多个目录项引用,所有硬链接路径地位平等,删除其中一个不会影响其他路径对文件的访问,直到最后一个硬链接被删除时文件数据才会被真正清除。在C#中实现硬链接的创建和解析,需要借助Windows提供的底层API完成操作。

C#创建NTFS硬链接
Windows系统提供了CreateHardLink函数用于创建硬链接,该函数位于kernel32.dll中,我们需要在C#中通过平台调用服务(P/Invoke)声明这个函数,再封装成可调用的方法。
声明API函数
首先需要在C#代码中声明CreateHardLink的外部函数,指定对应的DLL和调用规则:
using System;
using System.Runtime.InteropServices;
public class HardLinkHelper
{
// 声明CreateHardLink函数,返回bool表示创建是否成功
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern bool CreateHardLink(
string lpFileName, // 要创建的硬链接路径
string lpExistingFileName, // 已存在的目标文件路径
IntPtr lpSecurityAttributes // 安全属性,一般传IntPtr.Zero即可
);
}
封装创建方法
基于声明的API函数,我们可以封装一个通用的创建硬链接方法,同时处理错误信息的获取:
using System;
using System.Runtime.InteropServices;
public class HardLinkHelper
{
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern bool CreateHardLink(
string lpFileName,
string lpExistingFileName,
IntPtr lpSecurityAttributes
);
/// <summary>
/// 创建NTFS硬链接
/// </summary>
/// <param name="hardLinkPath">硬链接的完整路径</param>
/// <param name="targetFilePath">目标文件的完整路径</param>
/// <returns>创建成功返回true,失败返回false</returns>
public static bool CreateHardLinkFile(string hardLinkPath, string targetFilePath)
{
// 调用系统API创建硬链接
bool result = CreateHardLink(hardLinkPath, targetFilePath, IntPtr.Zero);
if (!result)
{
// 获取错误码,方便排查问题
int errorCode = Marshal.GetLastWin32Error();
Console.WriteLine($"创建硬链接失败,错误码:{errorCode}");
}
return result;
}
}
调用示例
使用封装好的方法创建硬链接的示例代码如下:
class Program
{
static void Main(string[] args)
{
string targetFile = @"C:testoriginal.txt";
string hardLinkFile = @"C:testhardlink.txt";
// 创建硬链接
bool success = HardLinkHelper.CreateHardLinkFile(hardLinkFile, targetFile);
if (success)
{
Console.WriteLine("硬链接创建成功");
}
else
{
Console.WriteLine("硬链接创建失败");
}
}
}
C#解析NTFS硬链接
解析硬链接主要是判断一个文件是否存在其他硬链接路径,以及获取所有指向同一数据块的硬链接路径。Windows提供了FindFirstFileNameW和FindNextFileNameW函数来实现这个功能。
声明解析相关API
首先声明解析硬链接需要用到的两个API函数:
using System;
using System.Runtime.InteropServices;
using System.Text;
public class HardLinkHelper
{
// 查找第一个硬链接名称
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern IntPtr FindFirstFileNameW(
string lpFileName,
uint dwFlags,
ref uint stringLength,
StringBuilder fileName
);
// 查找下一个硬链接名称
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern bool FindNextFileNameW(
IntPtr findHandle,
ref uint stringLength,
StringBuilder fileName
);
// 关闭查找句柄
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool FindClose(IntPtr findHandle);
}
封装解析方法
封装获取文件所有硬链接路径的方法:
using System;
using System.Runtime.InteropServices;
using System.Text;
using System.Collections.Generic;
public class HardLinkHelper
{
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern IntPtr FindFirstFileNameW(
string lpFileName,
uint dwFlags,
ref uint stringLength,
StringBuilder fileName
);
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern bool FindNextFileNameW(
IntPtr findHandle,
ref uint stringLength,
StringBuilder fileName
);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool FindClose(IntPtr findHandle);
/// <summary>
/// 获取文件的所有硬链接路径
/// </summary>
/// <param name="filePath">要查询的文件完整路径</param>
/// <returns>所有硬链接路径的列表</returns>
public static List<string> GetAllHardLinks(string filePath)
{
List<string> hardLinks = new List<string>();
uint stringLength = 1024;
StringBuilder fileName = new StringBuilder((int)stringLength);
// 查找第一个硬链接
IntPtr findHandle = FindFirstFileNameW(filePath, 0, ref stringLength, fileName);
if (findHandle != IntPtr.Zero && findHandle.ToInt64() != -1)
{
// 添加找到的第一个路径
hardLinks.Add(fileName.ToString());
// 循环查找后续硬链接
while (FindNextFileNameW(findHandle, ref stringLength, fileName))
{
hardLinks.Add(fileName.ToString());
}
// 关闭查找句柄
FindClose(findHandle);
}
return hardLinks;
}
}
解析调用示例
调用解析方法获取文件所有硬链接的示例:
class Program
{
static void Main(string[] args)
{
string targetFile = @"C:testoriginal.txt";
List<string> allHardLinks = HardLinkHelper.GetAllHardLinks(targetFile);
Console.WriteLine($"文件 {targetFile} 的所有硬链接路径:");
foreach (string link in allHardLinks)
{
Console.WriteLine(link);
}
}
}
注意事项
- 硬链接仅支持NTFS文件系统,在FAT32、exFAT等文件系统中无法使用。
- 硬链接不能跨卷创建,即目标文件和硬链接必须位于同一个磁盘分区。
- 不能为目录创建硬链接,Windows系统仅支持文件的硬链接操作。
- 调用API时如果失败,可以通过
Marshal.GetLastWin32Error()获取错误码,根据错误码排查权限不足、目标文件不存在等问题。