【问题标题】:How to check whether 2 DirectoryInfo objects are pointing to the same directory?如何检查 2 个 DirectoryInfo 对象是否指向同一个目录?
【发布时间】:2023-04-03 07:30:01
【问题描述】:

我有 2 个DirectoryInfo 对象,想检查它们是否指向同一个目录。除了比较他们的全名之外,还有其他更好的方法吗?请忽略链接的大小写。

这就是我所拥有的。

DirectoryInfo di1 = new DirectoryInfo(@"c:\temp");
DirectoryInfo di2 = new DirectoryInfo(@"C:\TEMP");

if (di1.FullName.ToUpperInvariant() == di2.FullName.ToUpperInvariant())
{ // they are the same
   ...   
}

谢谢。

【问题讨论】:

标签: c# directory


【解决方案1】:

在 Linux 下,您可以比较两个文件的 INode 编号,无论它们是否相同。但是在windows下是没有这个概念的,至少我知道没有。您需要使用 p/invoke 来解析链接(如果有)。

比较字符串是您能做的最好的事情。请注意,使用 String.Compare(str1, str2, StringComparison.OrdinalIgnoreCase) 比使用 ToUpperInvariant() 更快,因为它不会在堆上分配新字符串,也不会让 problems inherent in using a linguistic text comparison algorithm 比较文件路径。

【讨论】:

  • 这个回答有什么问题?为什么被标记下来了?我发现使用 String.Compare() 的技巧很好。
  • 这与问题中提供的解决方案基本相同。更好的方法是使用 Uri,它将处理不同的格式等。
  • “但是在Windows下没有这样的概念”:这是错误的,因此这个答案本质上是错误的。虽然 NFS 中的 INode 更可靠(实际上是有保证的),但可以强制 Windows 为您提供类似的信息。在相关帖子中查看此答案:stackoverflow.com/a/39399232/1082063
  • 如果您要确定两个目录信息对象是否引用同一个目录,这将无法解决问题。应该指出的是,要确定两个路径名是否引用同一个文件系统对象是非常困难的,因为可能存在联结、链接、网络共享等。
  • InvariantCultureIgnoreCase 通常应该避免使用——总是更喜欢OrdinalIgnoreCase,尤其是在文件系统中,因为文件名不是语言字符串,请参阅docs.microsoft.com/en-us/dotnet/standard/base-types/…
【解决方案2】:

不区分大小写的比较是最好的。将其提取到辅助类中,以防万一人类想出更好的方法。

public static class DirectoryInfoExtensions
{
    public static bool IsEqualTo(this DirectoryInfo left, DirectoryInfo right)
    {
        return left.FullName.ToUpperInvariant() == right.FullName.ToUpperInvariant();
    }
}

并使用:

if (di1.IsEqualTo(di2))
{
    // Code here
}

【讨论】:

    【解决方案3】:

    您可以改用 Uri 对象。但是,您的 Uri 对象必须指向这些目录中的“文件”。该文件实际上不必存在。

        private void CompareStrings()
        {
            string path1 = @"c:\test\rootpath";
            string path2 = @"C:\TEST\..\TEST\ROOTPATH";
            string path3 = @"C:\TeSt\RoOtPaTh\";
    
            string file1 = Path.Combine(path1, "log.txt");
            string file2 = Path.Combine(path2, "log.txt");
            string file3 = Path.Combine(path3, "log.txt");
    
            Uri u1 = new Uri(file1);
            Uri u2 = new Uri(file2);
            Uri u3 = new Uri(file3);
    
            Trace.WriteLine(string.Format("u1 == u2 ? {0}", u1 == u2));
            Trace.WriteLine(string.Format("u2 == u3 ? {0}", u2 == u3));
    
        }
    

    这将打印出来:

    u1 == u2 ? True
    u2 == u3 ? True
    

    【讨论】:

    • 这实际上应该是答案,因为它涵盖了诸如“\..\”之类的边缘情况并且更健壮,尽管它需要一些解决方法
    • 但是有一个问题,它将 %51 之类的东西翻译成字母而不是留下它们,所以如果你尝试这个路径:@"c:\test\rootQpath" @"C:\TEST\..\TEST\ROOT%51PATH" 它会返回 true
    • 虽然C:\ 可以工作,但如果路径采用C: 的形式(省略\ ),则会抛出UriFormatException,因为Path.Combine 将导致类似@ 987654329@
    【解决方案4】:

    灵感来自here:

    static public bool SameDirectory(string path1, string path2)
    {
        return (
            0 == String.Compare(
                System.IO.Path.GetFullPath(path1).TrimEnd('\\'),
                System.IO.Path.GetFullPath(path2).TrimEnd('\\'),
                StringComparison.InvariantCultureIgnoreCase))
            ;
    }    
    

    也适用于文件...

    (顺便说一句,理论上问题是重复的,但这是原始问题,另一个是回答最多的问题......)

    HTH

    【讨论】:

      【解决方案5】:

      我为最近的一个项目编写的一些扩展方法包括一个可以做到的:

          public static bool IsSame(this DirectoryInfo that, DirectoryInfo other)
          {
              // zip extension wouldn't work here because it truncates the longer 
              // enumerable, resulting in false positive
      
              var e1 = that.EnumeratePathDirectories().GetEnumerator();
              var e2 = other.EnumeratePathDirectories().GetEnumerator();
      
              while (true)
              {
                  var m1 = e1.MoveNext();
                  var m2 = e2.MoveNext();
                  if (m1 != m2) return false; // not same length
                  if (!m1) return true; // finished enumerating with no differences found
      
                  if (!e1.Current.Name.Trim().Equals(e2.Current.Name.Trim(), StringComparison.InvariantCultureIgnoreCase))
                      return false; // current folder in paths differ
              }
          }
      
          public static IEnumerable<DirectoryInfo> EnumeratePathDirectories(this DirectoryInfo di)
          {
              var stack = new Stack<DirectoryInfo>();
      
              DirectoryInfo current = di;
      
              while (current != null)
              {
                  stack.Push(current);
                  current = current.Parent;
              }
      
              return stack;
          }
      
          // irrelevant for this question, but still useful:
      
          public static bool IsSame(this FileInfo that, FileInfo other)
          {
              return that.Name.Trim().Equals(other.Name.Trim(), StringComparison.InvariantCultureIgnoreCase) &&
                     that.Directory.IsSame(other.Directory);
          }
      
          public static IEnumerable<DirectoryInfo> EnumeratePathDirectories(this FileInfo fi)
          {
              return fi.Directory.EnumeratePathDirectories();
          }
      
          public static bool StartsWith(this FileInfo fi, DirectoryInfo directory)
          {
              return fi.Directory.StartsWith(directory);
          }
      
          public static bool StartsWith(this DirectoryInfo di, DirectoryInfo directory)
          {
              return di.EnumeratePathDirectories().Any(d => d.IsSame(directory));
          }
      

      【讨论】:

        【解决方案6】:

        从 netstandard2.1 开始,终于有了一种几乎方便且独立于平台的方法来检查这一点:Path.GetRelativePath()

        var areEqual = Path.GetRelativePath(path1, path2) == ".";
        

        适用于绝对路径和相对路径。还能正确处理foo/../foo/bar == foo/bar 之类的情况。

        【讨论】:

        • 我现在看到您删除了另一个问题的答案,因为人们不喜欢重复的答案;但无论如何 - 这当然是可行的!
        猜你喜欢
        • 2017-01-20
        • 2015-07-07
        • 2012-08-22
        • 2011-04-18
        • 2021-08-06
        • 2020-01-10
        • 2011-03-09
        • 2023-01-13
        • 1970-01-01
        相关资源
        最近更新 更多