How to compare (directory) paths in C ++?

I am looking for a way to check if 2 lines are the same in terms of the path to the file system (directory). For example, the entire line from this set is the same in terms of the path to the file system: { /x , \x , //x , /x/ }, but the two - /x and /y are not, even if /y is a symbolic link on /x . The program I'm going to write should work for both Linux and windows, so I'm looking for a portable solution.

EDIT:

I use headers only for headers only, so the solution with boost::filesystem is not suitable for me. I know that windows API has UrlCompare , is there something like linux?

+4
source share
4 answers

Any non-Boost solution will include system code (which is hidden in Boost if you use Boost). And you will need to determine exactly what you mean by "match": should "./MyFile.xxx" and "MyFile.xxx" compare equal? What about "aaa/.../MyFile.xxx" and "MyFile.xxx" ?

The way I will handle this is to define a class with two data members, a std::string with a "prefix" (which would always be empty on Unix) and std::vector<std::string> with the whole path elements. This class will be used with the necessary function mapping and will use system code to implement the constructor; the constructor itself will be in the source file, and the source file will include a machine-specific header (usually using a separate directory for each option and selecting a header using -I or /I to indicate which directory to use). Things that may be included in the title:

 inline bool isPathSeparator( char ch ) { return ch == '/'; } std::string getHeader( std::string const& fullPathName ) { return ""; } bool charCompare( char lhs, char rhs ) { return lhs < rhs; } bool charMatch( char lhs, char rhs ) { return lhs == rhs; } 

for Unix, with:

 inline bool isPathSeparator( char ch ) { return ch == '/' || ch == '\\'; } std::string getHeader( std::string const& fullPathName ) { return fullPathName.size() > 2 && fullPathName[1] == ':' ? fullPathName.substr( 0, 2 ) : std::string(); } bool charCompare( char lhs, char rhs ) { return tolower( (unsigned char)lhs) < tolower( (unsigned char)rhs ); } bool charMatch( char lhs, char rhs ) { return tolower( (unsigned char)lhs ) == tolower( (unsigned char)rhs ); } 

for windows.

Then the constructor will use getHeader to initialize the header and input.begin() + header.size() over input.begin() + header.size() and input.end() , breaking the string into elements. If you encounter the element "." , ignore it, and for one of ".." use pop_back() to remove the top element of the path if the path is not empty. Subsequently, it is just a matter of defining comparators for using charCompare and charMatch for char and std::lexicographical_compare or std::equal (after checking that the sizes are equal) with a comparator for std::string (and probably more so for your new class ) Sort of:

 struct FileNameCompare { bool operator()( char lhs, char rhs ) const { return charCompare( lhs, rhs ); } bool operator()( std::string const& lhs, std::string const& rhs ) const { return std::lexicographical_compare( lhs.begin(), lhs.end(), rhs.begin(), rhs.end(), *this ); } bool operator()( FileName const& lhs, FileName const& rhs ) const { return (*this)( lhs.prefix, rhs.prefix ) || ( !(*this)( rhs.prefix, lhs.prefix ) && std::lexicographical_compare( lhs.elements.begin(), lhs.elements.end(), rhs.elements.begin(), rhs.elements.end(), *this ) ); } }; struct FileNameMatch { bool operator()( char lhs, char rhs ) const { return charMatch( lhs, rhs ); } bool operator()( std::string const& lhs, std::string const& rhs ) const { return lhs.size() == rhs.size() && std::equal( lhs.begin(), lhs.end(), rhs.begin(), *this ); } bool operator()( FileName const& lhs, FileName const& rhs ) const { return (*this)( lhs.prefix, rhs.prefix ) && lhs.elements.size() == rhs.elements.size() && std::equal( lhs.elements.begin(), lhs.elements.end(), rhs.elements.begin(), *this ); } }; 

gotta do the trick. (Just remember that operator()( char, char ) const must be in the source file, you cannot embed them in a header that will not include the system- charCompare header that defines charCompare and charMatch .)

+3
source

Use the boost :: filesystem library - this has a path comparison function.

EDIT: you can try apr - yes it is not C ++, however it will be portable.

+2
source

In terms of portability, the Boost file system library can be useful ( link to documentation ). To be more specific: path.hpp is most useful where you can use path comparison.

EDIT

This discussion on gmane.org considers the minimum version of boost::filesystem for the header only. In short: this does not exist. This way, you will eventually create your own abstraction library and provide it with cross-platform functionality.

Linux has dirent.h , which is the POSIX C library. For Windows, you have to use the Win32 API. However, there is also a so-called “directory-stream library”, which appears to be cross-platform, available here (the website is in German).

+1
source
 std::string path1 = "c:\\folder\\"; std::string path2 = "c:\\folder\\folder\\..\\"; boost::filesystem::equivalent(boost::filesystem::path(path1), boost::filesystem::path(path2) 

The code returns true because the folder is actually the same.

0
source

Source: https://habr.com/ru/post/1386320/


All Articles