如何在C#中创建硬链接?

如何在C#中创建硬链接? 请问任何代码片段?

[DllImport("Kernel32.dll", CharSet = CharSet.Unicode )] static extern bool CreateHardLink( string lpFileName, string lpExistingFileName, IntPtr lpSecurityAttributes ); 

用法:

CreateHardLink(newLinkPath,sourcePath, IntPtr.Zero);

BCL不提供此function,因此您必须使用p / invoke

 [DllImport("Kernel32.dll", CharSet = CharSet.Unicode )] static extern bool CreateHardLink( string lpFileName, string lpExistingFileName, IntPtr lpSecurityAttributes ); 

并使用它,例如

  CreateHardLink(@"c:\temp\New Link", @"c:\temp\Original File",IntPtr.Zero); 

如果你的意思是NTFS硬链接:

以下是( dotnetspark上的文字介绍 ):

遗憾的是,.NET Framework不支持硬链接和软链接。 因此,您需要深入了解Windows API以允许您的应用程序使用此function。 您可以使用一行代码创建一个硬链接,只需调用位于Kernel32.dll库中的Win32函数CreateHardLink()即可。 该function的定义如下:

 BOOL CreateHardLink( LPCTSTR lpFileName, LPCTSTR lpExistingFileName, LPSECURITY_ATTRIBUTES lpSecurityAttributes ); 

如果您只想创建文件的硬链接答案

 using System.Runtime.InteropServices; ... [DllImport("Kernel32.dll", CharSet = CharSet.Unicode )] static extern bool CreateHardLink( string lpFileName, string lpExistingFileName, IntPtr lpSecurityAttributes ); 

似乎是最好的。

但是如果你想创建一个文件夹的硬链接,那就有点棘手了。
在这里,我找到了一些代码来创建/删除文件夹硬链接(联结)。 我测试了代码,它运行正常。
我在这里发布代码,以防网站脱机:

JunctionPoint.cs

 // File: RollThroughLibrary/CreateMaps/JunctionPoint.cs // User: Adrian Hum/ // // Created: 2017-11-19 2:46 PM // Modified: 2017-11-19 6:10 PM using System; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Runtime.InteropServices; using System.Text; using Microsoft.Win32.SafeHandles; namespace CreateMaps { ///  /// Provides access to NTFS junction points in .Net. ///  [SuppressMessage("ReSharper", "InconsistentNaming")] [SuppressMessage("ReSharper", "UnusedMember.Local")] [SuppressMessage("ReSharper", "MemberCanBePrivate.Local")] [SuppressMessage("ReSharper", "FieldCanBeMadeReadOnly.Local")] public static class JunctionPoint { ///  /// The file or directory is not a reparse point. ///  private const int ERROR_NOT_A_REPARSE_POINT = 4390; ///  /// The reparse point attribute cannot be set because it conflicts with an existing attribute. ///  private const int ERROR_REPARSE_ATTRIBUTE_CONFLICT = 4391; ///  /// The data present in the reparse point buffer is invalid. ///  private const int ERROR_INVALID_REPARSE_DATA = 4392; ///  /// The tag present in the reparse point buffer is invalid. ///  private const int ERROR_REPARSE_TAG_INVALID = 4393; ///  /// There is a mismatch between the tag specified in the request and the tag present in the reparse point. ///  private const int ERROR_REPARSE_TAG_MISMATCH = 4394; ///  /// Command to set the reparse point data block. ///  private const int FSCTL_SET_REPARSE_POINT = 0x000900A4; ///  /// Command to get the reparse point data block. ///  private const int FSCTL_GET_REPARSE_POINT = 0x000900A8; ///  /// Command to delete the reparse point data base. ///  private const int FSCTL_DELETE_REPARSE_POINT = 0x000900AC; ///  /// Reparse point tag used to identify mount points and junction points. ///  private const uint IO_REPARSE_TAG_MOUNT_POINT = 0xA0000003; ///  /// This prefix indicates to NTFS that the path is to be treated as a non-interpreted /// path in the virtual file system. ///  private const string NonInterpretedPathPrefix = @"\??\"; [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] private static extern bool DeviceIoControl(IntPtr hDevice, uint dwIoControlCode, IntPtr InBuffer, int nInBufferSize, IntPtr OutBuffer, int nOutBufferSize, out int pBytesReturned, IntPtr lpOverlapped); [DllImport("kernel32.dll", SetLastError = true)] private static extern IntPtr CreateFile( string lpFileName, EFileAccess dwDesiredAccess, EFileShare dwShareMode, IntPtr lpSecurityAttributes, ECreationDisposition dwCreationDisposition, EFileAttributes dwFlagsAndAttributes, IntPtr hTemplateFile); ///  /// Creates a junction point from the specified directory to the specified target directory. ///  ///  /// Only works on NTFS. ///  /// The junction point path /// The target directory /// If true overwrites an existing reparse point or empty directory ///  /// Thrown when the junction point could not be created or when /// an existing directory was found and  if false ///  public static void Create(string junctionPoint, string targetDir, bool overwrite) { targetDir = Path.GetFullPath(targetDir); if (!Directory.Exists(targetDir)) throw new IOException("Target path does not exist or is not a directory."); if (Directory.Exists(junctionPoint)) { if (!overwrite) throw new IOException("Directory already exists and overwrite parameter is false."); } else { Directory.CreateDirectory(junctionPoint); } using (var handle = OpenReparsePoint(junctionPoint, EFileAccess.GenericWrite)) { var targetDirBytes = Encoding.Unicode.GetBytes(NonInterpretedPathPrefix + Path.GetFullPath(targetDir)); var reparseDataBuffer = new REPARSE_DATA_BUFFER { ReparseTag = IO_REPARSE_TAG_MOUNT_POINT, ReparseDataLength = (ushort)(targetDirBytes.Length + 12), SubstituteNameOffset = 0, SubstituteNameLength = (ushort)targetDirBytes.Length, PrintNameOffset = (ushort)(targetDirBytes.Length + 2), PrintNameLength = 0, PathBuffer = new byte[0x3ff0] }; Array.Copy(targetDirBytes, reparseDataBuffer.PathBuffer, targetDirBytes.Length); var inBufferSize = Marshal.SizeOf(reparseDataBuffer); var inBuffer = Marshal.AllocHGlobal(inBufferSize); try { Marshal.StructureToPtr(reparseDataBuffer, inBuffer, false); int bytesReturned; var result = DeviceIoControl(handle.DangerousGetHandle(), FSCTL_SET_REPARSE_POINT, inBuffer, targetDirBytes.Length + 20, IntPtr.Zero, 0, out bytesReturned, IntPtr.Zero); if (!result) ThrowLastWin32Error("Unable to create junction point."); } finally { Marshal.FreeHGlobal(inBuffer); } } } ///  /// Deletes a junction point at the specified source directory along with the directory itself. /// Does nothing if the junction point does not exist. ///  ///  /// Only works on NTFS. ///  /// The junction point path public static void Delete(string junctionPoint) { if (!Directory.Exists(junctionPoint)) { if (File.Exists(junctionPoint)) throw new IOException("Path is not a junction point."); return; } using (var handle = OpenReparsePoint(junctionPoint, EFileAccess.GenericWrite)) { var reparseDataBuffer = new REPARSE_DATA_BUFFER { ReparseTag = IO_REPARSE_TAG_MOUNT_POINT, ReparseDataLength = 0, PathBuffer = new byte[0x3ff0] }; var inBufferSize = Marshal.SizeOf(reparseDataBuffer); var inBuffer = Marshal.AllocHGlobal(inBufferSize); try { Marshal.StructureToPtr(reparseDataBuffer, inBuffer, false); int bytesReturned; var result = DeviceIoControl(handle.DangerousGetHandle(), FSCTL_DELETE_REPARSE_POINT, inBuffer, 8, IntPtr.Zero, 0, out bytesReturned, IntPtr.Zero); if (!result) ThrowLastWin32Error("Unable to delete junction point."); } finally { Marshal.FreeHGlobal(inBuffer); } try { Directory.Delete(junctionPoint); } catch (IOException ex) { throw new IOException("Unable to delete junction point.", ex); } } } ///  /// Determines whether the specified path exists and refers to a junction point. ///  /// The junction point path /// True if the specified path represents a junction point ///  /// Thrown if the specified path is invalid /// or some other error occurs ///  public static bool Exists(string path) { if (!Directory.Exists(path)) return false; using (var handle = OpenReparsePoint(path, EFileAccess.GenericRead)) { var target = InternalGetTarget(handle); return target != null; } } ///  /// Gets the target of the specified junction point. ///  ///  /// Only works on NTFS. ///  /// The junction point path /// The target of the junction point ///  /// Thrown when the specified path does not /// exist, is invalid, is not a junction point, or some other error occurs ///  public static string GetTarget(string junctionPoint) { using (var handle = OpenReparsePoint(junctionPoint, EFileAccess.GenericRead)) { var target = InternalGetTarget(handle); if (target == null) throw new IOException("Path is not a junction point."); return target; } } private static string InternalGetTarget(SafeFileHandle handle) { var outBufferSize = Marshal.SizeOf(typeof(REPARSE_DATA_BUFFER)); var outBuffer = Marshal.AllocHGlobal(outBufferSize); try { int bytesReturned; var result = DeviceIoControl(handle.DangerousGetHandle(), FSCTL_GET_REPARSE_POINT, IntPtr.Zero, 0, outBuffer, outBufferSize, out bytesReturned, IntPtr.Zero); if (!result) { var error = Marshal.GetLastWin32Error(); if (error == ERROR_NOT_A_REPARSE_POINT) return null; ThrowLastWin32Error("Unable to get information about junction point."); } var reparseDataBuffer = (REPARSE_DATA_BUFFER) Marshal.PtrToStructure(outBuffer, typeof(REPARSE_DATA_BUFFER)); if (reparseDataBuffer.ReparseTag != IO_REPARSE_TAG_MOUNT_POINT) return null; var targetDir = Encoding.Unicode.GetString(reparseDataBuffer.PathBuffer, reparseDataBuffer.SubstituteNameOffset, reparseDataBuffer.SubstituteNameLength); if (targetDir.StartsWith(NonInterpretedPathPrefix)) targetDir = targetDir.Substring(NonInterpretedPathPrefix.Length); return targetDir; } finally { Marshal.FreeHGlobal(outBuffer); } } private static SafeFileHandle OpenReparsePoint(string reparsePoint, EFileAccess accessMode) { var reparsePointHandle = new SafeFileHandle(CreateFile(reparsePoint, accessMode, EFileShare.Read | EFileShare.Write | EFileShare.Delete, IntPtr.Zero, ECreationDisposition.OpenExisting, EFileAttributes.BackupSemantics | EFileAttributes.OpenReparsePoint, IntPtr.Zero), true); if (Marshal.GetLastWin32Error() != 0) ThrowLastWin32Error("Unable to open reparse point."); return reparsePointHandle; } private static void ThrowLastWin32Error(string message) { throw new IOException(message, Marshal.GetExceptionForHR(Marshal.GetHRForLastWin32Error())); } [Flags] private enum EFileAccess : uint { GenericRead = 0x80000000, GenericWrite = 0x40000000, GenericExecute = 0x20000000, GenericAll = 0x10000000 } [Flags] private enum EFileShare : uint { None = 0x00000000, Read = 0x00000001, Write = 0x00000002, Delete = 0x00000004 } private enum ECreationDisposition : uint { New = 1, CreateAlways = 2, OpenExisting = 3, OpenAlways = 4, TruncateExisting = 5 } [Flags] private enum EFileAttributes : uint { Readonly = 0x00000001, Hidden = 0x00000002, System = 0x00000004, Directory = 0x00000010, Archive = 0x00000020, Device = 0x00000040, Normal = 0x00000080, Temporary = 0x00000100, SparseFile = 0x00000200, ReparsePoint = 0x00000400, Compressed = 0x00000800, Offline = 0x00001000, NotContentIndexed = 0x00002000, Encrypted = 0x00004000, Write_Through = 0x80000000, Overlapped = 0x40000000, NoBuffering = 0x20000000, RandomAccess = 0x10000000, SequentialScan = 0x08000000, DeleteOnClose = 0x04000000, BackupSemantics = 0x02000000, PosixSemantics = 0x01000000, OpenReparsePoint = 0x00200000, OpenNoRecall = 0x00100000, FirstPipeInstance = 0x00080000 } [StructLayout(LayoutKind.Sequential)] private struct REPARSE_DATA_BUFFER { ///  /// Reparse point tag. Must be a Microsoft reparse point tag. ///  public uint ReparseTag; ///  /// Size, in bytes, of the data after the Reserved member. This can be calculated by: /// (4 * sizeof(ushort)) + SubstituteNameLength + PrintNameLength + /// (namesAreNullTerminated ? 2 * sizeof(char) : 0); ///  public ushort ReparseDataLength; ///  /// Reserved; do not use. ///  public ushort Reserved; ///  /// Offset, in bytes, of the substitute name string in the PathBuffer array. ///  public ushort SubstituteNameOffset; ///  /// Length, in bytes, of the substitute name string. If this string is null-terminated, /// SubstituteNameLength does not include space for the null character. ///  public ushort SubstituteNameLength; ///  /// Offset, in bytes, of the print name string in the PathBuffer array. ///  public ushort PrintNameOffset; ///  /// Length, in bytes, of the print name string. If this string is null-terminated, /// PrintNameLength does not include space for the null character. ///  public ushort PrintNameLength; ///  /// A buffer containing the unicode-encoded path string. The path string contains /// the substitute name string and print name string. ///  [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x3FF0)] public byte[] PathBuffer; } } } 

用法:

 using CreateMaps; ... JunctionPoint.Create(@"C:\Temp\HardlinkFolderToCreate", @"C:\Temp\ExistingFolder", false); 
 Process.Start("mklink /H", String.Format("{0} {1}", link, target)); 

看看这个项目: Hardlink类