47

What is the best way to compare two paths in .Net to figure out if they point to the same file or directory?

  1. How would one verify that these are the same:

    c:\Some Dir\SOME FILE.XXX
    C:\\\SOME DIR\some file.xxx
    
  2. Even better: is there a way to verify that these paths point to the same file on some network drive:

    h:\Some File.xxx
    \\Some Host\Some Share\Some File.xxx
    

UPDATE:

Kent Boogaart has answered my first question correctly; but I`m still curious to see if there is a solution to my second question about comparing paths of files and directories on a network drive.

UPDATE 2 (combined answers for my two questions):

Question 1: local and/or network files and directories

c:\Some Dir\SOME FILE.XXX
C:\\\SOME DIR\some file.xxx

Answer: use System.IO.Path.GetFullPath as exemplified with:

var path1 = Path.GetFullPath(@"c:\Some Dir\SOME FILE.XXX");
var path2 = Path.GetFullPath(@"C:\\\SOME DIR\subdir\..\some file.xxx");

// outputs true
Console.WriteLine("{0} == {1} ? {2}", path1, path2, string.Equals(path1, path2, StringComparison.OrdinalIgnoreCase));

Question 2: local and/or network files and directories

Answer: Use the GetPath method as posted on http://briancaos.wordpress.com/2009/03/05/get-local-path-from-unc-path/

  • Your second example should have only one instead of three backslashs at the beginning, right? – Uwe Keim Sep 08 '11 at 08:10
  • You can find a similar question here: http://stackoverflow.com/questions/2281531/how-can-i-compare-directory-paths-in-c – mamoo Sep 08 '11 at 08:12
  • possible duplicate of [Best way to determine if two path reference to same file in C#](http://stackoverflow.com/questions/410705/best-way-to-determine-if-two-path-reference-to-same-file-in-c-sharp) – nawfal Dec 31 '13 at 13:08
  • .NET Core has [`Path.IsPathFullyQualified`](https://learn.microsoft.com/en-us/dotnet/api/system.io.path.ispathfullyqualified?view=netcore-3.1) – Vladimir Reshetnikov Jan 29 '20 at 00:51

11 Answers11

47
var path1 = Path.GetFullPath(@"c:\Some Dir\SOME FILE.XXX");
var path2 = Path.GetFullPath(@"C:\\\SOME DIR\subdir\..\some file.xxx");

// outputs true
Console.WriteLine("{0} == {1} ? {2}", path1, path2, string.Equals(path1, path2, StringComparison.OrdinalIgnoreCase));

Ignoring case is only a good idea on Windows. You can use FileInfo.FullName in a similar fashion, but Path will work with both files and directories.

Not sure about your second example.

Kent Boogaart
  • 175,602
  • 35
  • 392
  • 393
  • 3
    Why does `new FileInfo(@"c:\").Equals(new FileInfo(@"c:\"))` evaluate to `false`? That should really be the way to do it.. – Christopher King Sep 06 '16 at 03:52
  • 4
    When comparing directories, you should take into account the trailing slash. For example, `@"A:\dir"` won't equal `@"A:\dir\"` with `GetFullPath`. – tm1 May 04 '17 at 07:38
  • 6
    `Path.GetFullPath(@"C:\src")` returns `@"C:\src"` and `Path.GetFullPath(@"C:\src\")` returns `@"C:\src\"`. In other words, even though these paths are equivalent, the approach outlined above will fail in this corner case. – user3613932 Jul 26 '17 at 02:04
  • 2
    Why does this answer use OrdinalIgnoreCase and not CurrentCultureIgnoreCase? Those file name strings come from the user. To my reading, that means you need to use the current culture for correct comparison. Ordinal is only valid for machine generated strings, like parsing XML tags in a known schema. Have I misunderstood something? – srm Sep 15 '17 at 16:22
  • @ChristopherKing `FileInfo` does not override `Object.Equals` nor implement `IEquatable`, unfortunately. – Dai Feb 24 '19 at 10:21
  • Note that mounted drives could always be case sensitive even on Windows, but that's especially true now that WSL is a thing so this isn't particularly reliable. – Mike Marynowski Apr 29 '20 at 01:28
  • 3
    @srm because file paths are culturally independent data. See https://learn.microsoft.com/en-us/dotnet/standard/base-types/best-practices-strings#choosing-a-stringcomparison-member-for-your-method-call – LanYi Dec 07 '20 at 03:28
  • @LanYi That is the strongest argument I've heard yet for paths becoming a proper class type instead of just being strings! – srm Dec 07 '20 at 06:32
5

Although it's an old thread posting as i found one.

Using Path.GetFullpath I could solve my Issue eg.

Path.GetFullPath(path1).Equals(Path.GetFullPath(path2))

As per suggestion given in comment, to ignore case comparison

Path.GetFullPath(path1).Equals(Path.GetFullPath(path2),StringComparison.CurrentCultureIgnoreCase)
Hardik
  • 1,716
  • 6
  • 27
  • 41
  • 8
    This doesn't work in this case which returns `false`: `Path.GetFullPath(@"C:\tfs\").Equals(Path.GetFullPath(@"C:\TFS"))` – Dai Nov 27 '18 at 02:31
1

I liked @bob-ashcraft answer however I think it should be expanded a little. Here's mine (not enough rep to comment on his :( )

/// <summary>
/// Tests if paths are physically/logically the same.
/// Physical: C:\DATA == c:\\dAtA\\)
/// Logical: C:\DATA == \\SERVER\DATA)
/// Must have pathA write and pathB read permission to test for logical equality.
/// </summary>
public static bool TryIsSamePath(string pathA, string pathB, out string errorMsg)
{
    var ret = false;
    errorMsg = string.Empty;
    try
    {
    // If either are blank it's not valid.
    if (string.IsNullOrWhiteSpace(pathA)) { throw new ArgumentNullException(nameof(pathA)); }
    else if (string.IsNullOrWhiteSpace(pathB)) { throw new ArgumentNullException(nameof(pathB)); }

    // Test if they are the exact same physical path.
    ret = System.IO.Path.GetFullPath(pathA).Equals(System.IO.Path.GetFullPath(pathB));

    // If not physically the same, test for logical.
    // Create a temp file on pathA; if it exists on pathB too then they're the same.
    if (!ret)
    {
        var tempPathA = System.IO.Path.Combine(pathA, System.DateTime.Now.Ticks.ToString() + ".~");
        var tempPathB = System.IO.Path.Combine(pathB, System.IO.Path.GetFileName(tempPathA));
        using (var tempPathAFileStream = System.IO.File.Create(tempPathA)) { }
        ret = System.IO.File.Exists(tempPathB);
        System.IO.File.Delete(tempPathA);
    }
    }
    catch (Exception exc)
    {
    // Return the error message but don't rethrow.
    errorMsg = exc.Message;
    }
    return ret;
}
user566399
  • 11
  • 2
0

Nice syntax with the use of extension methods

You can have a nice syntax like this:

string path1 = @"c:\Some Dir\SOME FILE.XXX";
string path2 = @"C:\\\SOME DIR\subdir\..\some file.xxx";

bool equals = path1.PathEquals(path2); // true

With the implementation of an extension method:

public static class StringExtensions {
    public static bool PathEquals(this string path1, string path2) {
        return Path.GetFullPath(path1)
            .Equals(Path.GetFullPath(path2), StringComparison.InvariantCultureIgnoreCase);
    }
}

Thanks to Kent Boogaart for the nice example paths.

Bruno Zell
  • 7,761
  • 5
  • 38
  • 46
0

I had this problem too, but I tried a different approach, using the Uri class. I found it to be very promising so far :)

var sourceUri = new Uri(sourcePath);
var targetUri = new Uri(targetPath);

if (string.Compare(sourceUri.AbsoluteUri, targetUri.AbsoluteUri, StringComparison.InvariantCultureIgnoreCase) != 0 
|| string.Compare(sourceUri.Host, targetUri.Host, StringComparison.InvariantCultureIgnoreCase) != 0)
            {
// this block evaluates if the source path and target path are NOT equal
}
Jeff Moretti
  • 613
  • 5
  • 6
0

A very simple approach I use to determine if two path strings point to the same location is to create a temp file in Path1 and see if it shows up in Path2. It is limited to locations you have write-access to, but if you can live with that, it’s easy! Here’s my VB.NET code (which can easily be converted to C#) …

Public Function SamePath(Path1 As String, Path2 As String) As String

'  Returns: "T" if Path1 and Path2 are the same,
'           "F" if they are not, or
'               Error Message Text

Try
   Path1 = Path.Combine(Path1, Now.Ticks.ToString & ".~")
   Path2 = Path.Combine(Path2, Path.GetFileName(Path1))

   File.Create(Path1).Close

   If File.Exists(Path2) Then
      Path2 = "T"
   Else
      Path2 = "F"
   End If

   File.Delete(Path1)

Catch ex As Exception
   Path2 = ex.Message

End Try

Return Path2

End Function

I return the result as a string so I can provide an error message if the user enters some garbage. I’m also using Now.Ticks as a “guaranteed” unique file name but there are other ways, like Guid.NewGuid.

0

As reported by others, Path.GetFullPath or FileInfo.FullName provide normalized versions of local files. Normalizing a UNC path for comparison is quite a bit more involved but, thankfully, Brian Pedersen has posted a handy MRU (Method Ready to Use) to do exactly what you need on his blog, aptly titled Get local path from UNC path. Once you add this to your code, you then have a static GetPath method that takes a UNC path as its sole argument and normalizes it to a local path. I gave it a quick try and it works as advertised.

Michael Sorens
  • 35,361
  • 26
  • 116
  • 172
0

This code compares equality by first checking for \ or / at the end of a path and ignoring those endings if they exist there.

Linux version:

public static bool PathEquals(this string left, string right) =>
    left.TrimEnd('/', '\\') == right.TrimEnd('/', '\\');

Windows version (case insensitive):

public static bool PathEquals(this string left, string right) =>
    string.Equals(left.TrimEnd('/', '\\'), right.TrimEnd('/', '\\'), StringComparison.OrdinalIgnoreCase);
trinalbadger587
  • 1,905
  • 1
  • 18
  • 36
-1

Only one way to ensure that two paths references the same file is to open and compare files. At least you can instantiate FileInfo object and compare properties like: CreationTime, FullName, Size, etc. In some approximation it gives you a guarantee that two paths references the same file.

sll
  • 61,540
  • 22
  • 104
  • 156
  • 1
    Well, for local files (at least files on the same filesystem), I would hope that you don't need to. For my second case, perhaps you are right, but that's why I'm asking the quetion.... –  Sep 08 '11 at 08:16
-1

you can use FileInfo!

string Path_test_1="c:\\main.h";
string Path_test_2="c:\\\\main.h";

var path1=new FileInfo(Path_test_1)
var path2=new FileInfo(Path_test_2)
if(path1.FullName==path2.FullName){

//two path equals
}
coonooo
  • 205
  • 1
  • 4
-4

Why not create a hash of each file and compare them? If they are the same, you can be reasonably sure they are the same file.

Scott
  • 999
  • 7
  • 13