How can I compare (directory) in C #?

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

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

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

  • \temp if the current working directory is located on drive C:\
  • temp if current working directory is C:\
  • C:\temp.
  • C:\temp...\

If itโ€™s important to consider the current working directory, I can figure it out myself, so itโ€™s not so important. Trailing points are deleted in the windows, so these paths should really be equal - but they are not divided into unix, so in mono I expect other results.

Case sensitivity is optional. Paths may or may not exist, and the user may or may not have permissions on the path - I would prefer a fast reliable method that does not require I / O (therefore checking for absence), but if something is built - I would also satisfied with something "good" ...

+63
c # filesystems path
Feb 17 2018-10-17
source share
12 answers

From this answer, this method can handle several cases:

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

See more in the original answer. Call it that:

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

Should work for both file paths and directories.

+24
Jan 11 '14 at 3:20
source share

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

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

Or, if you want to start with DirectoryInfo :

 String.Compare( dirinfo1.FullName.TrimEnd('\\'), dirinfo2.FullName.TrimEnd('\\'), StringComparison.InvariantCultureIgnoreCase) 
+86
Feb 17 '10 at 15:11
source share

There are several shortcuts to implementing paths in .NET. There are many complaints about this. Patrick Smackey , creator of NDepend, publishes an open source library

+10
Feb 17 2018-10-17T00
source share

I understand this is an old post, but all the answers are ultimately based on a textual comparison of the two names. Trying to get two "normalized" names that take into account the many possible ways of referencing the same file object is almost impossible. There are problems such as: connections, symbolic links, shared network files (links to the same file in different manners), etc. Etc.

The question specifically requested that the solution does not require I / O, but if you are going to deal with network paths, you absolutely need to do IO: there are times when it is simply impossible to determine from any local path manipulation whether links to two files refer to the same physical file. (This can be easily understood as follows: suppose that the file server has a connection to the Windows directory somewhere inside a common subtree. In this case, the file can be referenced either directly or through the connection. But the connection is on the file server, and therefore for the client itโ€™s just it is impossible to determine, only through local information, that two reference file names refer to the same physical file: the information is simply not available locally for the client.Thus, it is absolutely necessary to perform a minimum IO - for example, open two file object descriptors - determine whether links refer to the same physical file.)

The following solution performs some I / O, but correctly determines whether two file system links are semantically identical, that is, they refer to the same file object. (if no file specification relates to a valid file object, all bids are disabled):

  public static bool AreDirsEqual(string dirName1, string dirName2) { //Optimization: if strings are equal, don't bother with the IO bool bRet = string.Equals(dirName1, dirName2, StringComparison.OrdinalIgnoreCase); if (!bRet) { //NOTE: we cannot lift the call to GetFileHandle out of this routine, because we _must_ // have both file handles open simultaneously in order for the objectFileInfo comparison // to be guaranteed as valid. using (SafeFileHandle directoryHandle1 = GetFileHandle(dirName1), directoryHandle2 = GetFileHandle(dirName2)) { BY_HANDLE_FILE_INFORMATION? objectFileInfo1 = GetFileInfo(directoryHandle1); BY_HANDLE_FILE_INFORMATION? objectFileInfo2 = GetFileInfo(directoryHandle2); bRet = objectFileInfo1 != null && objectFileInfo2 != null && (objectFileInfo1.Value.FileIndexHigh == objectFileInfo2.Value.FileIndexHigh) && (objectFileInfo1.Value.FileIndexLow == objectFileInfo2.Value.FileIndexLow) && (objectFileInfo1.Value.VolumeSerialNumber == objectFileInfo2.Value.VolumeSerialNumber); } } return bRet; } 

The idea for this was derived from a response from Warren Stevens in a similar question that I posted on SuperUser: https://superuser.com/a/881966/241981

+5
Sep 08 '16 at 19:58
source share
  System.IO.Path.GetFullPath(pathA).Equals(System.IO.Path.GetFullPath(PathB)); 
+3
Feb 17 '10 at 14:50
source share

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

UPD: Oh, I didnโ€™t take into account your desire not to use any I / O.

+3
Feb 17 '10 at 02:53
source share

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".) These are different FullName properties that are different.

You might be able to make a recursive method to check the properties of the name of each parent, given your two DirectoryInfo classes, to ensure that the full path is the same.

EDIT : Does this work for your situation? Create a console application and paste it into the entire Program.cs file. Provide two DirectoryInfo objects with AreEquals (), and it will return True if they are the same directory. You may be able to configure this AreEquals() method as an extension method in DirectoryInfo if you want, so you can just do 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
Feb 17 2018-10-17T00
source share

You can use Minimatch, Node.js' minimash port.

 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 why the AllowWindowsPaths = true parameter is needed:

On Windows-style paths, the Minimatch syntax was designed for Linux-style paths (with a slash only). In particular, it uses a backslash as an escape character, so it cannot just accept Windows-style paths. My C # version saves this behavior.

To suppress this and allow both backslashes and slashes as path separators (in templates or input), set the AllowWindowsPaths parameter:

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

Passing this option will completely disable escape characters.

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

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

+1
Jun 26 '14 at 3:17
source share

Microsoft has implemented similar methods, although they are not as useful as the answers above:

+1
Dec 02 '15 at 9:44
source share
 bool equals = myDirectoryInfo1.FullName == myDirectoryInfo2.FullName; 

?

0
Feb 17 2018-10-17
source share
 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
Nov 03 '10 at
source share
 bool Equals(string path1, string path2) { return new Uri(path1) == new Uri(path2); } 

The Uri constructor normalizes the path.

0
Apr 04 '14 at 21:32
source share



All Articles