ChatGPT解决这个技术问题 Extra ChatGPT

How to build a full path string (safely) from separate strings?

Does C++ have any equivalent to python's function os.path.join? Basically, I'm looking for something that combines two (or more) parts of a file path so that you don't have to worry about making sure the two parts fit together perfectly. If it's in Qt, that would be cool too.

Basically I spent an hour debugging some code and at least part of it was because root + filename had to be root/ + filename, and I'm looking to avoid that in the future.

Possibly distantly related: stackoverflow.com/questions/5772992/… (specifically, related to that question is boost's complete)

A
Azeem

Only as part of Boost.Filesystem library. Here is an example:

#include <iostream>
#include <boost/filesystem.hpp>

namespace fs = boost::filesystem;

int main ()
{
    fs::path dir ("/tmp");
    fs::path file ("foo.txt");
    fs::path full_path = dir / file;
    std::cout << full_path << std::endl;
    return 0;
}

Here is an example of compiling and running (platform specific):

$ g++ ./test.cpp -o test -lboost_filesystem -lboost_system
$ ./test 
/tmp/foo.txt

This is also in TR2, which is likely to start shipping with compilers next year.
@Vlad : Yeah, it's not easily discoverable, but I hate clicking on Boost doc links and belatedly realizing I'm looking at an old version, so I edit people's version-specific links when I come across them. :-P
@ildjarn: Which seems to work great now... but wait until they change something about the site or the docs for the given library. It is worse than leaving the version-specific link from then on.
@Fred : Obviously if the functionality or question happens to be version-specific, I don't change the URL. In this case, it isn't, so I did.
With C++17 use #include <filesystem>, namespace fs = std::filesystem;. With C++14 use #include <experimental/filesystem>, namespace fs = std::experimental::filesystem;.
M
Michael Burr

Check out QDir for that:

QString path = QDir(dirPath).filePath(fileName);

Beware that Qt is GPL. Might be a deal breaker for many uses.
@RustyX it is LGPL, to be precise.
i love this answer, no futzing with strings and concatenation, let the framework figure it out.
S
Shawn Blakesley

Similar to @user405725's answer (but not using boost), and mentioned by @ildjarn in a comment, this functionality is available as part of std::filesystem. The following code compiles using Homebrew GCC 9.2.0_1 and using the flag --std=c++17:

#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;

int main() 
{
    fs::path dir ("/tmp");
    fs::path file ("foo.txt");
    fs::path full_path = dir / file;
    std::cout << full_path << std::endl;
    return 0;
}

As of C++17, this was merged into the (non-experimental) <filesystem> header. See en.cppreference.com/w/cpp/filesystem.
Thank you so much, this answer is a way to go in case if c++ 17 is available on the project.
in my case its just joining them directly (and not putting a / or \ between them)
A
Azeem

At least in Unix / Linux, it's always safe to join parts of a path by /, even if some parts of the path already end in /, i.e. root/path is equivalent to root//path.

In this case, all you really need is to join things on /. That said, I agree with other answers that boost::filesystem is a good choice if it is available to you because it supports multiple platforms.


QT is agnostic to path separator. If you print absolute path of a file on Windows the output is "C:/Users/Name/MyFile.txt" with the / (unix) separator. boost::filesystem is great but, in my opinion, if the project is Qt-based there's no need to add a dependecy for boost library.
A
Azeem

If you want to do this with Qt, you can use QFileInfo constructor:

QFileInfo fi( QDir("/tmp"), "file" );
QString path = fi.absoluteFilePath();

k
kainjow

With C++11 and Qt you can do this:

QString join(const QString& v) {
    return v;
}

template<typename... Args>
QString join(const QString& first, Args... args) {
    return QDir(first).filePath(join(args...));
}

Usage:

QString path = join("/tmp", "dir", "file"); // /tmp/dir/file

A
Azeem

In Qt, just use / in code when using Qt API (QFile, QFileInfo). It will do the right thing on all platforms. If you have to pass a path to a non-Qt function, or want to format it for displaying it to the user, use QDir:toNativeSeparators() e.g.:

QDir::toNativeSeparators( path );

It will replace / by the native equivalent (i.e. \ on Windows). The other direction is done via QDir::fromNativeSeparators().