web-dev-qa-db-ja.com

C#で(ディレクトリ)パスを比較するにはどうすればよいですか?

2つのDirectoryInfoオブジェクトがある場合、それらをセマンティックの等価性について比較するにはどうすればよいですか?たとえば、次のパスはすべてC:\tempと等しいと見なされる必要があります。

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

以下は、C:\tempと等しい場合とそうでない場合があります。

  • \temp現在の作業ディレクトリがドライブにある場合C:\
  • temp現在の作業ディレクトリがC:\の場合
  • C:\temp.
  • C:\temp...\

現在の作業ディレクトリを考慮することが重要である場合、私は自分でそれを理解することができますので、それはそれほど重要ではありません。後続のドットはウィンドウで削除されるため、これらのパスは実際には等しいはずです-しかし、Unixでは削除されないので、モノラルでは他の結果が期待できます。

大文字と小文字の区別はオプションです。パスは存在する場合と存在しない場合があり、ユーザーにはパスへのアクセス許可がある場合とない場合があります。 -私も「十分に良い」ものに満足しています...

69
Eamon Nerbonne

この回答 から、このメソッドはいくつかのEdgeケースを処理できます。

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

元の回答の詳細。次のように呼び出します:

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

ファイルとディレクトリの両方のパスで機​​能するはずです。

33
nawfal

GetFullPathは、大文字と小文字の違い(Path.GetFullPath("test") != Path.GetFullPath("TEST"))と末尾のスラッシュを除いて、作業を行うようです。したがって、次のコードは正常に機能するはずです。

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

または、DirectoryInfoで開始する場合:

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

.NETでのパスの実装にはいくつかの欠点があります。それについて多くの苦情があります。 Patrick Smacchia (NDependの作成者)は、 一般的な複雑なパス操作の処理を可能にするオープンソースライブラリ を公開しました。アプリケーションのパスで多くの比較操作を行う場合、このライブラリが役立つ場合があります。

11
Steven

P/Invoking GetFinalPathNameByHandle() が最も信頼できるソリューションであるようです。

UPD:おっと、I/Oを使用しないというあなたの希望を考慮しませんでした

4
Igor Korkhov
 System.IO.Path.GetFullPath(pathA).Equals(System.IO.Path.GetFullPath(PathB));
2
Asad Butt

マイクロソフトは同様の方法を実装していますが、上記の回答ほど有用ではありません。

2
Chris Xue

Node.jsのミニマッチのポートであるミニマッチを使用できます。

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


理由を見る the AllowWindowsPaths = trueオプションが必要です。

Windowsスタイルのパスでは、Minimatchの構文はLinuxスタイルのパス用に設計されました(スラッシュのみ)。特に、バックスラッシュをエスケープ文字として使用するため、Windowsスタイルのパスを単純に受け入れることはできません。私のC#バージョンはこの動作を保持します。

これを抑制し、パスセパレーターとしてバックスラッシュとスラッシュの両方を(パターンまたは入力で)許可するには、AllowWindowsPathsオプションを設定します。

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

このオプションを渡すと、エスケープ文字が完全に無効になります。

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

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

1
vulcan raven

「名前」プロパティは同等です。取る:

_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_(この場合は「スクラッチ」。dir3== "4760"。)異なるのはFullNameプロパティのみです。

2つのDirectoryInfoクラスが指定されている場合、再帰的なメソッドを実行して各親のNameプロパティを調べ、完全なパスが同じであることを確認できます。

[〜#〜] edit [〜#〜]:これはあなたの状況で機能しますか?コンソールアプリケーションを作成し、これをProgram.csファイル全体に貼り付けます。 2つのDirectoryInfoオブジェクトをAreEquals()関数に提供すると、それらが同じディレクトリである場合は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;
        }
    }
}
_
1
Andy Shellam
bool Equals(string path1, string path2)
{
    return new Uri(path1) == new Uri(path2);
}

Uriコンストラクターはパスを正規化します。

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

0
herzmeister
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;
        }
    }
}
0
Denis