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
How to Use the Ternary Operator Inside an Interpolated String
Get Month Name from Month Number
How to Convert a Timespan to a Formatted String
How to Create Custom Config Section in App.Config
ASP.NET MVC Ambiguous Action Methods
C# - Approach for Saving User Settings in a Wpf Application
C#: How to Make It Harder for Hacker/Cracker to Get Around or Bypass the Licensing Check
There Is No Argument Given That Corresponds to the Required Formal Parameter - .Net Error
Managing Multiple Selections with Mvvm
How to Pass Parameters to Another Process in C#
C# Wpf Navigation Between Pages (Views)
C# Elegant Way to Check If a Property's Property Is Null
Pass Connection String to Code-First Dbcontext
Order of Items in Classes: Fields, Properties, Constructors, Methods
Linq Select Distinct with Anonymous Types
Executing Ssis 2012 Package That Has Script Components from External Application