42

有没有办法使用 C# 判断文件是真实链接还是符号链接?

我已经翻阅了MSDN W32 文档,但找不到任何可以检查的内容。我从这里使用 CreateSymbolicLink,它工作正常。

4

8 回答 8

57
private bool IsSymbolic(string path)
{
    FileInfo pathInfo = new FileInfo(path);
    return pathInfo.Attributes.HasFlag(FileAttributes.ReparsePoint);
}
于 2014-10-20T20:04:55.950 回答
26

在我的博客上发布了一些符号链接的源代码,可让您:

  • 创建符号链接
  • 检查路径是否是符号链接
  • 检索符号链接的目标

它还包含您可能希望扩展的 NUnit 测试用例。

肉的一点是:

private static SafeFileHandle getFileHandle(string path)
{
    return CreateFile(path, genericReadAccess, shareModeAll, IntPtr.Zero, openExisting,
        fileFlagsForOpenReparsePointAndBackupSemantics, IntPtr.Zero);
}

public static string GetTarget(string path)
{
    SymbolicLinkReparseData reparseDataBuffer;

    using (SafeFileHandle fileHandle = getFileHandle(path))
    {
        if (fileHandle.IsInvalid)
        {
            Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
        }

        int outBufferSize = Marshal.SizeOf(typeof(SymbolicLinkReparseData));
        IntPtr outBuffer = IntPtr.Zero;
        try
        {
            outBuffer = Marshal.AllocHGlobal(outBufferSize);
            int bytesReturned;
            bool success = DeviceIoControl(
                fileHandle.DangerousGetHandle(), ioctlCommandGetReparsePoint, IntPtr.Zero, 0,
                outBuffer, outBufferSize, out bytesReturned, IntPtr.Zero);

            fileHandle.Close();

            if (!success)
            {
                if (((uint)Marshal.GetHRForLastWin32Error()) == pathNotAReparsePointError)
                {
                    return null;
                }
                Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
            }

            reparseDataBuffer = (SymbolicLinkReparseData)Marshal.PtrToStructure(
                outBuffer, typeof(SymbolicLinkReparseData));
        }
        finally
        {
            Marshal.FreeHGlobal(outBuffer);
        }
    }
    if (reparseDataBuffer.ReparseTag != symLinkTag)
    {
        return null;
    }

    string target = Encoding.Unicode.GetString(reparseDataBuffer.PathBuffer,
        reparseDataBuffer.PrintNameOffset, reparseDataBuffer.PrintNameLength);

    return target;
}

那是:

于 2012-03-27T03:02:49.510 回答
7

下面是一个将文件和目录与指向文件的链接和指向目录的链接区分开来的示例。

指向文件或目录的链接保持它们自己的属性(创建日期、权限)与它们的目标分开。

可以删除文件链接(例如使用“del”)而不影响目标文件。

可以删除目录链接(例如“rmdir”)而不影响目标目录。使用“rd /s”时要小心。这将删除目录链接目标。

FileAttributes签入FileInfo和的关键标志DirectoryInfoFileAttributes.ReparsePoint

static void Main( string[] args ) {
FileInfo file_info = new FileInfo(args[0]);
DirectoryInfo directory_info = new DirectoryInfo(args[0]);

bool is_file = file_info.Exists;
bool is_directory = directory_info.Exists;

if (is_file) {
    Console.WriteLine(file_info.ToString() + " is a file");

    if ( file_info.Attributes.HasFlag(FileAttributes.ReparsePoint) )
        Console.WriteLine(args[0] + " is a Windows file link");
}
else if (is_directory) {
    Console.WriteLine(directory_info.ToString() + " is a directory");

    if ( directory_info.Attributes.HasFlag(FileAttributes.ReparsePoint) )
        Console.WriteLine(args[0] + " is a Windows directory link");
}
于 2014-02-04T16:33:09.667 回答
3

证明上述答案不可靠。最后我从MSDN得到了正确的解决方案:

要确定指定目录是否为挂载文件夹,首先调用 GetFileAttributes 函数并检查返回值中的 FILE_ATTRIBUTE_REPARSE_POINT 标志,以查看该目录是否具有关联的重解析点。如果是,请使用 FindFirstFile 和 FindNextFile 函数获取 WIN32_FIND_DATA 结构的 dwReserved0 成员中的重解析标记。要确定重解析点是否是已安装的文件夹(而不是某种其他形式的重解析点),请测试标记值是否等于值 IO_REPARSE_TAG_MOUNT_POINT。有关详细信息,请参阅重解析点。

于 2018-08-14T11:27:38.980 回答
0

GetFileInformationByHandle填充了一个BY_HANDLE_FILE_INFORMATION结构,该结构有一个字段dwFileAttributes,其中位设置了有关文件属性的信息(详细信息here)。特别是,看看掩码...:

FILE_ATTRIBUTE_REPARSE_POINT 1024 0x0400

具有关联重分析点的文件或目录,或作为符号链接的文件。

于 2009-09-28T02:42:13.727 回答
0

根据对Stack Overflow 问题的回答Find if a file is a symbolic link in PowerShell,获取文件的System.IO.FileAttributes(通过File.GetAttributes),并测试 ReparsePoint 位,工作。如果设置了该位,则它是符号链接连接点。如果不是,它是一个常规文件(或硬链接)。

于 2010-02-12T22:31:41.743 回答
0

MonoPosix库提供 API 来检查文件是否为符号链接:

public bool IsSymlink(string filePath)
   => UnixFileSystemInfo.GetFileSystemEntry(filePath).IsSymbolicLink;
于 2020-01-28T08:05:19.720 回答
0

我知道我迟到了,但在研究同样的问题时发现了这个讨论

我发现以下内容对我有用,所以我想我会发布以防其他人使用

它的工作原理是这样的:-

var provider = ReparsePointFactory.Provider;

var link = provider.GetLink(@"c:\program files (x86)\common files\microsoft shared\vgx\vgx.dll");

MsgBox("Link Type: " + link.Type.ToString + " Link Target: " + link.Target + " Link Attributes: " + link.Attributes.ToString);

https://github.com/NCodeGroup/NCode.ReparsePoints https://www.nuget.org/packages/NCode.ReparsePoints/

于 2020-10-10T16:26:34.693 回答