Best Way to Determine If Two Path Reference to Same File in C#

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

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 can I determine that several file paths formats point to the same physical location

As Oded states this is tricky to do in .Net. You could possibly cheat (depening on your exact requirements and permissions etc) by writing a file with a long randomly generated filename to the location and then seeing if you can see it from the other location. Bit of a hack but this is a pretty sound test I think, rather than relying on resolving mapped drives etc etc.

Ok many apologies for the VB - it's all I've got on this tiny netbook... C# wouldn't be too different...

usage eg

If sameLocation("\\machineName\c$\rootPath\subPath","\\machineName\shareName") Then...

Public Function sameLocation(ByVal sPath1 As String, ByVal sPath2 As String) As TriState
Dim sFile As String = randomFilename()
Dim sFullPath1 As String = sPath1 & "\" & sFile
Dim sFullPath2 As String = sPath2 & "\" & sFile
Dim bReturn As Boolean = False
Try
Dim fs As New FileStream(sFullPath1, FileMode.CreateNew)
fs.Close()
Catch ex As Exception
Return TriState.UseDefault
End Try

Try
bReturn = File.Exists(sFullPath2)
Catch ex As Exception
Return TriState.UseDefault
End Try

File.Delete(sFullPath1)
Return bReturn
End Function

Public Function randomFilename() As String
Dim r As New Random
Randomize(My.Computer.Clock.TickCount)
Dim sb As New StringBuilder
Dim chars As Int16 = 100
While chars > 0
chars -= 1
sb.Append(Chr(r.Next(26) + 65))
End While
Return sb.ToString
End Function

You could add more security, ie reading the timestamp etc...

Detect if two paths are the same

You could have a method like this to check if equal:

public static bool PathsSame(string pth1, string pth2)
{
string fName = System.IO.Path.GetRandomFileName();
string fPath = System.IO.Path.Combine(pth1, fName);
System.IO.File.Create(fPath);
string nPath = System.IO.Path.Combine(pth2, fName);
bool same = File.Exists(nPath);
System.IO.File.Delete(fPath);
return same;
}

This simulates the behaviour of checking if paths are the same you can create a file with unique name and check if it exists in other directory. Then you could delete the file created because it is not needed anymore. This is not the best solutiton, however it may be sufficient.

This also doesn't handle errors that can occur. For error handling look at this: https://msdn.microsoft.com/en-us/library/vstudio/as2f1fez(v=vs.110).aspx

Best way to determine if two path reference to same file in Windows?

Open both files with CreateFile, call GetFileInformationByHandle for both, and compare dwVolumeSerialNumber, nFileIndexLow, nFileIndexHigh. If all three are equal they both point to the same file:

GetFileInformationByHandle function

BY_HANDLE_FILE_INFORMATION Structure

Check if two file names reference to the same file

If you use Path.GetFullPath on both names they should resolve to the same string:

string fullPath1 = Path.GetFullPath(absolutePath);
string fullPath2 = Path.GetFullPath(relativePath);

Then fullPath1 should equal fullPath2 if they reference the same file. Make sure that you do a case insensitive comparison as Windows filenames are case insensitive.

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.

How do you check to see if two different file reference strings refer to the same file?

On a POSIX system you can use stat() to check if they have the same inode number on the same filesystem.

You should also check the generation number, to handle a race condition due to the file being deleted and a new file getting its inode number between the two calls.

#include <sys/stat.h>

static bool is_same_file (const char *f1, const char *f2) {
struct stat s1, s2;
if (stat(f1, &s1) < 0)) {
perror("stat f1");
return false;
}
if (stat(f2, &s2) < 0)) {
perror("stat f2");
return false;
}
return s1.st_dev == s2.st_dev && s1.st_ino == st.st_ino && s1.st_gen == s2.st_gen;
}

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