You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET如何获取规范文件路径以判断路径指向同一文件?

解决方案:在.NET 7+中判断路径是否指向同一文件/文件夹

针对你的需求,这里提供两种适配不同场景的方案,分别对应「纯文本比较(不访问文件系统)」和「适配文件系统规则(轻度访问)」的要求:

方案一:基于操作系统默认行为的纯文本比较

这个方案无需访问文件系统,仅通过规范化路径+系统默认的路径比较逻辑实现,能覆盖大部分通用场景:

  1. 先用Path.GetFullPath将路径转换为绝对路径,自动处理相对路径、./..等冗余部分;
  2. 调用Path.Equals方法,该方法会根据操作系统的默认文件系统行为选择比较规则:
    • Windows:默认不区分大小写(如C:\A.TXT和c:\a.txt会被判定为相同)
    • Linux/Unix:严格区分大小写
    • macOS:遵循系统默认的APFS设置(默认不区分,若为区分大小写的APFS卷则不适用)

代码示例:

public static bool ArePathsSame(string path1, string path2)
{
    string fullPath1 = Path.GetFullPath(path1);
    string fullPath2 = Path.GetFullPath(path2);
    return Path.Equals(fullPath1, fullPath2);
}

局限:无法处理同一系统内不同文件系统的差异,比如Windows上设置为区分大小写的NTFS文件夹、macOS上的区分大小写APFS卷。

方案二:适配文件系统卷的大小写规则

如果需要精准适配具体文件系统的大小写规则(比如区分大小写的NTFS),需要轻度访问文件系统查询卷的元数据(不会打开或修改文件),再选择对应比较逻辑:

跨平台辅助方法:判断文件系统是否区分大小写

using System.ComponentModel;
using System.Runtime.InteropServices;

public static class FileSystemHelper
{
    public static bool IsFileSystemCaseSensitive(string path)
    {
        string rootPath = Path.GetPathRoot(path) ?? throw new ArgumentException("无效路径", nameof(path));

        if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
        {
            return IsWindowsFileSystemCaseSensitive(rootPath);
        }
        else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) || RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
        {
            return IsUnixFileSystemCaseSensitive(path);
        }

        throw new PlatformNotSupportedException("不支持的操作系统");
    }

    private static bool IsWindowsFileSystemCaseSensitive(string rootPath)
    {
        const uint FILE_CASE_SENSITIVE_SEARCH = 0x00000001;
        uint flags = 0;
        StringBuilder fsName = new(256);

        if (!GetVolumeInformation(rootPath, null, 0, out _, out _, out flags, fsName, fsName.Capacity))
        {
            throw new Win32Exception();
        }

        return (flags & FILE_CASE_SENSITIVE_SEARCH) != 0;
    }

    private static bool IsUnixFileSystemCaseSensitive(string path)
    {
        Statfs buf = new();
        if (statfs(path, ref buf) != 0)
        {
            throw new Win32Exception();
        }

        const long ST_CASEINSENSITIVE = 0x00000002;
        return (buf.f_flags & ST_CASEINSENSITIVE) == 0;
    }

    [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    private static extern bool GetVolumeInformation(
        string lpRootPathName,
        StringBuilder? lpVolumeNameBuffer,
        int nVolumeNameSize,
        out uint lpVolumeSerialNumber,
        out uint lpMaximumComponentLength,
        out uint lpFileSystemFlags,
        StringBuilder lpFileSystemNameBuffer,
        int nFileSystemNameSize);

    [DllImport("libc", SetLastError = true)]
    private static extern int statfs(string path, ref Statfs buf);

    [StructLayout(LayoutKind.Sequential)]
    private struct Statfs
    {
        public long f_type;
        public long f_bsize;
        public long f_blocks;
        public long f_bfree;
        public long f_bavail;
        public long f_files;
        public long f_ffree;
        public ulong f_fsid;
        public long f_namelen;
        public long f_frsize;
        public long f_flags;
        public long[] f_spare;
    }
}

路径比较方法

public static bool ArePathsSame(string path1, string path2)
{
    string fullPath1 = Path.GetFullPath(path1);
    string fullPath2 = Path.GetFullPath(path2);

    // 先检查是否在同一根目录,避免跨文件系统的情况
    if (!Path.GetPathRoot(fullPath1).Equals(Path.GetPathRoot(fullPath2), StringComparison.Ordinal))
    {
        return false;
    }

    bool isCaseSensitive = FileSystemHelper.IsFileSystemCaseSensitive(fullPath1);
    StringComparison comparison = isCaseSensitive ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase;
    return fullPath1.Equals(fullPath2, comparison);
}

路径规范化方法(Canonical)

public static string CanonicalizePath(string path)
{
    string fullPath = Path.GetFullPath(path);
    bool isCaseSensitive = FileSystemHelper.IsFileSystemCaseSensitive(fullPath);
    return isCaseSensitive ? fullPath : fullPath.ToLowerInvariant();
}

说明:这个方案会查询路径所在卷的文件系统属性,能准确处理区分大小写的NTFS、APFS等场景,且不会打开或修改文件,仅读取卷的元数据。

注意事项

  • 两种方案都不会处理符号链接、硬链接等情况,符合你“不关心这类路径是否指向同一实体”的要求;
  • 方案一的优势是完全不访问文件系统,性能更高;方案二的优势是精准适配文件系统规则,适用范围更广。

内容的提问来源于stack exchange,提问作者ispiro

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 19:05:23