如何比较 C# 中的(目录)路径?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2281531/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-07 01:00:52  来源:igfitidea点击:

How can I compare (directory) paths in C#?

c#.netpathfilesystems

提问by Eamon Nerbonne

If I have two DirectoryInfoobjects, how can I compare them for semantic equality? For example, the following paths should all be considered equal to C:\temp:

如果我有两个DirectoryInfo对象,我如何比较它们的语义相等性?例如,以下路径都应视为等于C:\temp

  • C:\temp
  • C:\temp\
  • C:\temp\.
  • C:\temp\x\..\..\temp\.
  • C:\temp
  • C:\temp\
  • C:\temp\.
  • C:\temp\x\..\..\temp\.

The following may or may not be equal to C:\temp:

以下可能等于也可能不等于C:\temp

  • \tempif the current working directory is on drive C:\
  • tempif the current working directory is C:\
  • C:\temp.
  • C:\temp...\
  • \temp如果当前工作目录在驱动器上 C:\
  • temp如果当前工作目录是 C:\
  • C:\temp.
  • C:\temp...\

If it's important to consider the current working directory, I can figure that out myself, so that's not that important. Trailing dots are stripped in windows, so those paths really should be equal - but they aren't stripped in unix, so under mono I'd expect other results.

如果考虑当前工作目录很重要,我可以自己弄清楚,所以这不是那么重要。尾随点在窗口中被剥离,所以这些路径真的应该是相等的 - 但它们在 unix 中没有被剥离,所以在单声道下我期望其他结果。

Case sensitivity is optional. The paths may or may not exist, and the user may or may not have permissions to the path - I'd prefer a fast robust method that doesn't require any I/O (so no permission checking), but if there's something built-in I'd be happy with anything "good enough" too...

区分大小写是可选的。路径可能存在也可能不存在,用户可能有也可能没有路径的权限 - 我更喜欢一种不需要任何 I/O 的快速健壮的方法(所以没有权限检查),但如果有构建-我也会对任何“足够好”的东西感到满意......

采纳答案by nawfal

From this answer, this method can handle a few edge cases:

这个答案,这个方法可以处理一些边缘情况:

public static string NormalizePath(string path)
{
    return Path.GetFullPath(new Uri(path).LocalPath)
               .TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar)
               .ToUpperInvariant();
}

More details in the original answer. Call it like:

原始答案中的更多详细信息。像这样称呼它:

bool pathsEqual = NormalizePath(path1) == NormalizePath(path2);

Should work for both file and directory paths.

应该适用于文件和目录路径。

回答by herzmeister

bool equals = myDirectoryInfo1.FullName == myDirectoryInfo2.FullName;

?

?

回答by Asad

 System.IO.Path.GetFullPath(pathA).Equals(System.IO.Path.GetFullPath(PathB));

回答by Igor Korkhov

It seems that P/Invoking GetFinalPathNameByHandle()would be the most reliable solution.

似乎 P/Invoking GetFinalPathNameByHandle()将是最可靠的解决方案。

UPD: Oops, I didn't take into account your desire not to use any I/O

UPD:哎呀,我没有考虑到你不想使用任何 I/O

回答by Andy Shellam

The "Name" properties are equal. Take:

“名称”属性是相等的。拿:

DirectoryInfo dir1 = new DirectoryInfo("C:\Scratch");
DirectoryInfo dir2 = new DirectoryInfo("C:\Scratch\");
DirectoryInfo dir3 = new DirectoryInfo("C:\Scratch\4760");
DirectoryInfo dir4 = new DirectoryInfo("C:\Scratch\4760\..\");

dir1.Name == dir2.Name and dir2.Name == dir4.Name("Scratch" in this case. dir3 == "4760".) It's only the FullName properties that are different.

dir1.Name == dir2.Name and dir2.Name == dir4.Name(在本例中为“Scratch”。dir3 ==“4760”。)只有 FullName 属性不同。

You might be able to do a recursive method to examine the Name properties of each parent given your two DirectoryInfo classes to ensure the complete path is the same.

给定您的两个 DirectoryInfo 类,您可能能够执行递归方法来检查每个父项的 Name 属性,以确保完整路径相同。

EDIT: does this work for your situation? Create a Console Application and paste this over the entire Program.cs file. Provide two DirectoryInfo objects to the AreEquals() function and it will return True if they're the same directory. You might be able to tweak this AreEquals()method to be an extension method on DirectoryInfo if you like, so you could just do myDirectoryInfo.IsEquals(myOtherDirectoryInfo);

编辑:这对你的情况有效吗?创建一个控制台应用程序并将其粘贴到整个 Program.cs 文件中。向 AreEquals() 函数提供两个 DirectoryInfo 对象,如果它们是同一目录,它将返回 True。AreEquals()如果您愿意,您可以将此方法调整为 DirectoryInfo 上的扩展方法,因此您可以这样做myDirectoryInfo.IsEquals(myOtherDirectoryInfo);

using System;
using System.Diagnostics;
using System.IO;
using System.Collections.Generic;

namespace ConsoleApplication3
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine(AreEqual(
                new DirectoryInfo("C:\Scratch"),
                new DirectoryInfo("C:\Scratch\")));

            Console.WriteLine(AreEqual(
                new DirectoryInfo("C:\Windows\Microsoft.NET\Framework"),
                new DirectoryInfo("C:\Windows\Microsoft.NET\Framework\v3.5\1033\..\..")));

            Console.WriteLine(AreEqual(
                new DirectoryInfo("C:\Scratch\"),
                new DirectoryInfo("C:\Scratch\4760\..\..")));

            Console.WriteLine("Press ENTER to continue");
            Console.ReadLine();
        }

        private static bool AreEqual(DirectoryInfo dir1, DirectoryInfo dir2)
        {
            DirectoryInfo parent1 = dir1;
            DirectoryInfo parent2 = dir2;

            /* Build a list of parents */
            List<string> folder1Parents = new List<string>();
            List<string> folder2Parents = new List<string>();

            while (parent1 != null)
            {
                folder1Parents.Add(parent1.Name);
                parent1 = parent1.Parent;
            }

            while (parent2 != null)
            {
                folder2Parents.Add(parent2.Name);
                parent2 = parent2.Parent;
            }

            /* Now compare the lists */

            if (folder1Parents.Count != folder2Parents.Count)
            {
                // Cannot be the same - different number of parents
                return false;
            }

            bool equal = true;

            for (int i = 0; i < folder1Parents.Count && i < folder2Parents.Count; i++)
            {
                equal &= folder1Parents[i] == folder2Parents[i];
            }

            return equal;
        }
    }
}

回答by Steven

There are some short comes to the implementation of paths in .NET. There are many complaints about it. Patrick Smacchia, the creator of NDepend, published an open source library that enables handling of common and complex path operations. If you do a lot of compare operations on paths in your application, this library might be useful to you.

在 .NET 中实现路径有一些短板。对此有很多抱怨。NDepend 的创建者Patrick Smacchia发布了一个开源库,可以处理常见和复杂的路径操作。如果您对应用程序中的路径进行大量比较操作,这个库可能对您有用。

回答by VladV

GetFullPathseems to do the work, except for case difference (Path.GetFullPath("test") != Path.GetFullPath("TEST")) and trailing slash. So, the following code should work fine:

GetFullPath似乎可以完成这项工作,但大小写差异 ( Path.GetFullPath("test") != Path.GetFullPath("TEST")) 和尾部斜杠除外。因此,以下代码应该可以正常工作:

String.Compare(
    Path.GetFullPath(path1).TrimEnd('\'),
    Path.GetFullPath(path2).TrimEnd('\'), 
    StringComparison.InvariantCultureIgnoreCase)

Or, if you want to start with DirectoryInfo:

或者,如果你想开始DirectoryInfo

String.Compare(
    dirinfo1.FullName.TrimEnd('\'),
    dirinfo2.FullName.TrimEnd('\'), 
    StringComparison.InvariantCultureIgnoreCase)

回答by Denis

using System;
using System.Collections.Generic;
using System.Text;

namespace EventAnalysis.IComparerImplementation
{

    public sealed class FSChangeElemComparerByPath : IComparer<FSChangeElem>
    {
        public int Compare(FSChangeElem firstPath, FSChangeElem secondPath)
        {
            return firstPath.strObjectPath == null ?
                (secondPath.strObjectPath == null ? 0 : -1) :
                (secondPath.strObjectPath == null ? 1 : ComparerWrap(firstPath.strObjectPath, secondPath.strObjectPath));
        }

        private int ComparerWrap(string stringA, string stringB)
        {
            int length = 0;
            int start = 0;
            List<string> valueA = new List<string>();
            List<string> valueB = new List<string>();

            ListInit(ref valueA, stringA);
            ListInit(ref valueB, stringB);

            if (valueA.Count != valueB.Count)
            {
                length = (valueA.Count > valueB.Count)
                           ? valueA.Count : valueB.Count;

                if (valueA.Count != length)
                {
                    for (int i = 0; i < length - valueA.Count; i++)
                    {
                        valueA.Add(string.Empty);
                    }
                }
                else
                {
                    for (int i = 0; i < length - valueB.Count; i++)
                    {
                        valueB.Add(string.Empty);
                    }
                }
            }

            else
                length = valueA.Count;

            return RecursiveComparing(valueA, valueB, length, start);
        }

        private void ListInit(ref List<string> stringCollection, string stringToList)
        {
            foreach (string s in stringToList.Remove(0, 2).Split('\'))
            {
                stringCollection.Add(s);
            }
        }

        private int RecursiveComparing(List<string> valueA, List<string> valueB, int length, int start)
        {
            int result = 0;

            if (start != length)
            {
                if (valueA[start] == valueB[start])
                {
                    result = RecursiveComparing(valueA, valueB, length, ++start);
                }
                else
                {
                    result = String.Compare(valueA[start], valueB[start]);
                }
            }
            else
                return 0;

            return result;
        }
    }
}

回答by boris

bool Equals(string path1, string path2)
{
    return new Uri(path1) == new Uri(path2);
}

Uri constructor normalizes the path.

Uri 构造函数规范化路径。

回答by vulcan raven

You can use Minimatch, a port of Node.js' minimatch.

您可以使用 Minimatch,这是 Node.js 的 minimatch 的一个端口。

var mm = new Minimatcher(searchPattern, new Options { AllowWindowsPaths = true });

if (mm.IsMatch(somePath))
{
    // The path matches!  Do some cool stuff!
}

var matchingPaths = mm.Filter(allPaths);


See whythe AllowWindowsPaths = trueoption is necessary:


了解为什么需要AllowWindowsPaths = true选项:

On Windows-style paths Minimatch's syntax was designed for Linux-style paths (with forward slashes only). In particular, it uses the backslash as an escape character, so it cannot simply accept Windows-style paths. My C# version preserves this behavior.

To suppress this, and allow both backslashes and forward slashes as path separators (in patterns or input), set the AllowWindowsPathsoption:

var mm = new Minimatcher(searchPattern, new Options { AllowWindowsPaths = true });

Passing this option will disable escape characters entirely.

在 Windows 风格的路径上 Minimatch 的语法是为 Linux 风格的路径设计的(仅带有正斜杠)。特别是,它使用反斜杠作为转义字符,因此它不能简单地接受 Windows 样式的路径。我的 C# 版本保留了这种行为。

要抑制这种情况,并允许反斜杠和正斜杠作为路径分隔符(在模式或输入中),请设置 AllowWindowsPaths选项:

var mm = new Minimatcher(searchPattern, new Options { AllowWindowsPaths = true });

传递此选项将完全禁用转义字符。

Nuget:http://www.nuget.org/packages/Minimatch/

Nuget:http ://www.nuget.org/packages/Minimatch/

GitHub:https://github.com/SLaks/Minimatch

GitHub:https : //github.com/SLaks/Minimatch