How would I compare 2 strings to determine if they refer to the same path in Win32 using C/C++?
While this will handle a lot of cases it misses some things:
See this question: Best way to determine if two path reference to same file in C#
The question is about C#, but the answer is just the Win32 API call GetFileInformationByHandle
.
use the GetFullPathName from kernel32.dll, this will give you the absolute path of the file. Then compare it against the other path that you have using a simple string compare
edit: code
TCHAR buffer1[1000];
TCHAR buffer2[1000];
TCHAR buffer3[1000];
TCHAR buffer4[1000];
GetFullPathName(TEXT("C:\\Temp\\..\\autoexec.bat"),1000,buffer1,NULL);
GetFullPathName(TEXT("C:\\autoexec.bat"),1000,buffer2,NULL);
GetFullPathName(TEXT("\\autoexec.bat"),1000,buffer3,NULL);
GetFullPathName(TEXT("C:/autoexec.bat"),1000,buffer4,NULL);
_tprintf(TEXT("Path1: %s\n"), buffer1);
_tprintf(TEXT("Path2: %s\n"), buffer2);
_tprintf(TEXT("Path3: %s\n"), buffer3);
_tprintf(TEXT("Path4: %s\n"), buffer4);
the code above will print the same path for all three path representations.. you might want to do a case insensitive search after that
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
Open both files and use GetFinalPathNameByHandle() against the HANDLE
s. Then compare the paths.
Since C++17 you can use the standard filesystem library. Include it using #include <filesystem>
. You can access it even in older versions of C++, see footnote.
The function you are looking for is equivalent
, under namespace std::filesystem
:
bool std::filesystem::equivalent(const std::filesystem::path& p1, const filesystem::path& p2 );
To summarize from the documentation: this function takes two paths as parameters and returns true if they reference the same file or directory, false otherwise. There is also a noexcept
overload that takes a third parameter: an std::error_code
in which to save any possible error.
#include <filesystem>
#include <iostream>
//...
int main() {
std::filesystem::path p1 = ".";
std::filesystem::path p2 = fs::current_path();
std::cout << std::filesystem::equivalent(p1, p2);
//...
}
Output:
1
To use this library in versions prior to C++17 you have to enable experimental language features in your compiler and include the library in this way: #include <experimental/filesystem>
. You can then use its functions under the namespace std::experimental::filesystem
. Please note that the experimental filesystem library may differ from the C++17 one. See the documentation here.
For example:
#include <experimental/filesystem>
//...
std::experimental::filesystem::equivalent(p1, p2);
A simple string comparison is not sufficient for comparing paths for equality. In windows it's quite possible for c:\foo\bar.txt and c:\temp\bar.txt to point to exactly the same file via symbolic and hard links in the file system.
Comparing paths properly essentially forces you to open both files and compare low level handle information. Any other method is going to have flaky results.
Check out this excellent post Lucian made on the subject. The code is in VB but it's pretty translatable to C/C++ as he PInvoke'd most of the methods.
http://blogs.msdn.com/vbteam/archive/2008/09/22/to-compare-two-filenames-lucian-wischik.aspx