How to Compare (Directory) Paths in C#

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

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.

Verifying path equality with .Net


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.

How do I compare relative file or directory paths in C#?

The answer you linked in your post should actually work for you. GetFullPath doesn't just resolve full paths to an absolute path, but also resolves relative path to absolute paths.
Just don't forget to use the code to provided in the linked answer to resolve trailing slashes and add code to replace / with \ (as mentioned by Henk)

How to compare file paths from JsonConfigurationSources and Directory.GetFiles properly?

/config.json is an absolute path and config.json is a relative path, so to compare them you have to convert the relative path into absolute path by giving it a directory.

But this isn't the real problem, the document is not detailed enough (In fact it doesn't mention about this at all).

When you add a path by AddJsonFile extension method, it will automatically call FileConfigurationSource.ResolveFileProvider.

If no file provider has been set, for absolute Path, this will creates a physical file provider for the nearest existing directory.

This method convert the absolute path into a relative path, that's why /config.json becomes config.json, the directory info is put into an auto-generated file provider.

So to use the API correctly, you need change:

jsonConfigurationSource.Path

to:

jsonConfigurationSource.FileProvider.GetFileInfo(jsonConfigurationSource.Path).PhysicalPath

Or you can provide a FileProvider:

configurationBuilder.AddJsonFile(new NullFileProvider(), jsonFilePath, fileIsOptional, reloadConfigurationOnFileChange);

c# file path string comparison case insensitivity

From MSDN:

The string behavior of the file system, registry keys and values, and environment variables is best represented by StringComparison.OrdinalIgnoreCase.

And:

When interpreting file names, cookies, or anything else where a combination such as "å" can appear, ordinal comparisons still offer the most transparent and fitting behavior.

Therefore it's simply:

String.Equals(fileNameA, fileNameB, StringComparison.OrdinalIgnoreCase)

(I always use the static Equals call in case the left operand is null)

Compare paths & ignoring case of drive letter

You can use String.Equals() to compare two pathes (strings).

The following returns true:

var equal = String.Equals(@"C:\MyPath\MyConfig.json", @"c:\MyPath\MyConfig.json", StringComparison.OrdinalIgnoreCase); //or StringComparison.InvariantCultureIgnoreCase

UPDATE (after question update)

You should compare root and rest part of string:

var path1 = @"C:\MyPath\MyConfig.json";
var path2 = @"c:\MyPath\myConfig.json";

var rootEqual = String.Equals(Path.GetPathRoot(path1), Path.GetPathRoot(path2), StringComparison.OrdinalIgnoreCase); // true

var withoutRootEqual = String.Equals(path1.Substring(Path.GetPathRoot(path1).Length), path2.Substring(Path.GetPathRoot(path2).Length)); //false

var equal = rootEqual && withoutRootEqual;

Using this approach the results are:

"C:\MyPath\MyConfig.json" && "C:\MyPath\MyConfig.json" -> true
"C:\MyPath\MyConfig.json" && "c:\MyPath\MyConfig.json" -> true
"C:\MyPath\MyConfig.json" && "C:\MyPath\myConfig.json" -> false
"C:\MyPath\MyConfig.json" && "c:\MyPath\myConfig.json" -> false

Note: this will work on Windows only because root in Linux is different, but needed result can be achieved by the similar way.

Best way to determine if two path reference to same file in C#

As far as I can see (1) (2) (3) (4), the way JDK7 does it, is by calling GetFileInformationByHandle on the files and comparing dwVolumeSerialNumber, nFileIndexHigh and nFileIndexLow.

Per MSDN:

You can compare the VolumeSerialNumber and FileIndex members returned in the BY_HANDLE_FILE_INFORMATION structure to determine if two paths map to the same target; for example, you can compare two file paths and determine if they map to the same directory.

I do not think this function is wrapped by .NET, so you will have to use P/Invoke.

It might or might not work for network files. According to MSDN:

Depending on the underlying network components of the operating system and the type of server connected to, the GetFileInformationByHandle function may fail, return partial information, or full information for the given file.

A quick test shows that it works as expected (same values) with a symbolic link on a Linux system connected using SMB/Samba, but that it cannot detect that a file is the same when accessed using different shares that point to the same file (FileIndex is the same, but VolumeSerialNumber differs).

Comparing two paths in C#. When do I use case-sensitivity?

You can pinvoke the Shell API function SHParseDisplayName, then call the CompareIDs method on the IShellFolder interface returned by SHGetDesktopFolder.

If you can drop XP support you can use Microsoft's Windows-API-Code-Pack. Microsoft.WindowsAPICodePack.Shell.ShellObject.Equals would do the comparison.

How to check whether 2 DirectoryInfo objects are pointing to the same directory?

Under Linux you could compare the INode numbers of the two files wheather they are identical. But under Windows there is no such concept, at least not that I know off. You would need to use p/invoke to resolve the links if any.

Comparing strings is the best you can do. Note that using String.Compare(str1, str2, StringComparison.OrdinalIgnoreCase) is faster than your approach of ToUpperInvariant() as it doesn't allocate new strings on the heap and won't suffer problems inherent in using a linguistic text comparison algorithm to compare file paths.



Related Topics



Leave a reply



Submit