检查文件是真实文件还是符号链接

发布于 2024-08-05 18:54:47 字数 226 浏览 6 评论 0原文

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

我已经深入研究了 MSDN W32 文档 ,并且找不到任何内容来检查这一点。我在这里使用 CreateSymbolicLink,它工作正常。

Is there a way to tell using C# if a file is real or a symbolic link?

I've dug through the MSDN W32 docs, and can't find anything for checking this. I'm using CreateSymbolicLink from here, and it's working fine.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

不再见 2024-08-12 18:54:47
private bool IsSymbolic(string path)
{
    FileInfo pathInfo = new FileInfo(path);
    return pathInfo.Attributes.HasFlag(FileAttributes.ReparsePoint);
}
private bool IsSymbolic(string path)
{
    FileInfo pathInfo = new FileInfo(path);
    return pathInfo.Attributes.HasFlag(FileAttributes.ReparsePoint);
}
一杆小烟枪 2024-08-12 18:54:47

我有一些 符号链接的源代码发布在我的blog 允许您:

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

它还包含您可能希望扩展的 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;
}

即:

  • 使用 CreateFile()
  • 调用 DeviceIoControl() 来获取重解析点数据(注意:它可能是一个连接点!)
  • 查看 < a href="http://msdn.microsoft.com/en-us/library/windows/hardware/ff552012%28v=vs.85%29.aspx" rel="nofollow noreferrer">返回的数据结构检查。 重新解析标记会告诉您如果它是连接点或符号链接。这可能就是您想做的全部。

I have some source code for symlinks posted on my blog that will allow you to:

  • create symlinks
  • check whether a path is a symlink
  • retrieve the target of a symlink

It also contains NUnit test cases, that you may wish to extend.

The meaty bit is:

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;
}

That is:

偷得浮生 2024-08-12 18:54:47

从 .NET 6 开始,您可以使用:
FileSystemInfo.LinkTarget 属性

属性说明:

获取位于 FullName 中的链接的目标路径,如果此 FileSystemInfo 实例不代表链接,则返回 null

例如:

static bool IsSymbolicLink(string path)
{
    FileInfo file = new FileInfo(path);
    return file.LinkTarget != null;
}

Starting with .NET 6 you can use:
FileSystemInfo.LinkTarget Property

Property description:

Gets the target path of the link located in FullName, or null if this FileSystemInfo instance doesn't represent a link.

For example:

static bool IsSymbolicLink(string path)
{
    FileInfo file = new FileInfo(path);
    return file.LinkTarget != null;
}
与他有关 2024-08-12 18:54:47

下面是区分文件和目录以及文件链接和目录链接的示例。

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

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

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

用于检查 FileInfoDirectoryInfo 的关键 FileAttributes 标志是 FileAttributes.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");
}

Here is an example of differentiating files and directories from links to files and links to directories.

Links to either files or directories maintain their own attributes (creation date, permissions) separate from their targets.

File links can be deleted (e.g. using "del") without affecting the target file.

Directory links can be removed (e.g. "rmdir") without affecting the target directory. Take care when using "rd /s". This WILL remove the directory link target.

The key FileAttributes flag to check in both FileInfo and DirectoryInfo is FileAttributes.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");
}
メ斷腸人バ 2024-08-12 18:54:47

事实证明上述答案并不可靠。
最后我从 MSDN

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

It proves the above answers are not reliable.
Finally I got the right solution from MSDN:

To determine if a specified directory is a mounted folder, first call the GetFileAttributes function and inspect the FILE_ATTRIBUTE_REPARSE_POINT flag in the return value to see if the directory has an associated reparse point. If it does, use the FindFirstFile and FindNextFile functions to obtain the reparse tag in the dwReserved0 member of the WIN32_FIND_DATA structure. To determine if the reparse point is a mounted folder (and not some other form of reparse point), test whether the tag value equals the value IO_REPARSE_TAG_MOUNT_POINT. For more information, see Reparse Points.

七禾 2024-08-12 18:54:47

GetFileInformationByHandle 填充 BY_HANDLE_FILE_INFORMATION 结构,其中有一个字段 dwFileAttributes,其中位使用有关文件属性的信息进行设置(详细信息此处< /a>)。特别是,看看 mask 的部分......:

FILE_ATTRIBUTE_REPARSE_POINT 1024 0x0400

具有以下内容的文件或目录
关联的重分析点或文件
这是一个符号链接。

GetFileInformationByHandle fills a BY_HANDLE_FILE_INFORMATION structure which has a field dwFileAttributes where bits are set with info about the file's attributes (details here). In particular, look at the bit at mask...:

FILE_ATTRIBUTE_REPARSE_POINT 1024 0x0400

A file or directory that has an
associated reparse point, or a file
that is a symbolic link.

如若梦似彩虹 2024-08-12 18:54:47

根据 这个答案 Stack Overflow 问题找出文件是否是 PowerShell 中的符号链接,获取System.IO.FileAttributes 文件(通过 File.GetAttributes),并测试ReparsePoint 位,有效。如果该位已设置,则它是符号链接或连接点。如果不是,则它是常规文件(或硬链接)。

According to this answer to Stack Overflow question Find out whether a file is a symbolic link in PowerShell, getting the System.IO.FileAttributes for the file (via File.GetAttributes), and testing for the ReparsePoint bit, works. If the bit is set, it is a symlink or a junction point. If not, it is a regular file (or hardlink).

高跟鞋的旋律 2024-08-12 18:54:47

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

public bool IsSymlink(string filePath)
   => UnixFileSystemInfo.GetFileSystemEntry(filePath).IsSymbolicLink;

The library MonoPosix provides API to check if a file is a symbolic link:

public bool IsSymlink(string filePath)
   => UnixFileSystemInfo.GetFileSystemEntry(filePath).IsSymbolicLink;
甜妞爱困 2024-08-12 18:54:47

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

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

它的工作原理如下:-

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/

I know I am late to the party but found this discussion when researching same question

I found the below worked for me so thought I would post in case of use to anyone else

It works like this:-

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/

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文