Как построить полную строку пути (безопасно) из отдельных строк?

91

Есть ли в C ++ эквивалент функции Python os.path.join? По сути, я ищу что-то, что объединяет две (или более) части пути к файлу, чтобы вам не приходилось беспокоиться о том, чтобы эти две части идеально подходили друг к другу. Если бы это было в Qt, это тоже было бы круто.

Обычно я потратил час на отладку некоторого кода, и, по крайней мере, часть этого была вызвана root + filenameнеобходимостью root/ + filename, и я стараюсь избежать этого в будущем.

sas4740
источник
Возможно, отдаленно связанный: stackoverflow.com/questions/5772992/… (в частности, связанный с этим вопросом - boost complete)
Гонки легкости на орбите

Ответы:

45

Проверьте QDir для этого:

QString path = QDir(dirPath).filePath(fileName);
Стивен Чу
источник
3
Помните, что Qt - это GPL. Может быть препятствием для многих применений.
rustyx 09
4
@RustyX это LGPL, если быть точным.
Pa_ 02
99

Только в составе библиотеки Boost.Filesystem . Вот пример:

#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;
}

Вот пример компиляции и запуска (зависит от платформы):

$ g++ ./test.cpp -o test -lboost_filesystem -lboost_system
$ ./test 
/tmp/foo.txt
Азим
источник
1
Это также относится к TR2, поставки которого, вероятно, начнутся с компиляторами в следующем году.
ildjarn 09
1
@Vlad: Да, это нелегко обнаружить, но я ненавижу щелкать ссылки на документы Boost и с опозданием осознавать, что смотрю на старую версию, поэтому я редактирую ссылки для конкретных версий, когда сталкиваюсь с ними. :-P
ildjarn 09
1
@ildjarn: Кажется, сейчас это отлично работает ... но подождите, пока они что-то не изменят на сайте или в документации для данной библиотеки. Это хуже, чем оставлять с этого момента ссылку на конкретную версию.
Фред Нурк,
1
@Fred: Очевидно, если функциональность или вопрос зависят от версии, я не меняю URL. В данном случае это не так, я так и сделал.
ildjarn 09
1
@ildjarn: Как вы прогнозируете, что данная библиотека изменится в будущем, чтобы вы могли знать, будут ли все ответы, которые вы редактируете, иметь смысл для всех будущих версий?
Fred Nurk
24

Подобно ответу @ user405725 (но без использования boost) и упомянутому @ildjarn в комментарии, эта функция доступна как часть std :: filesystem . Следующий код компилируется с использованием Homebrew GCC 9.2.0_1 и с использованием флага --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;
}
Шон Блейксли
источник
4
Начиная с C ++ 17, это было объединено в (не экспериментальный) заголовок <filesystem>. См. En.cppreference.com/w/cpp/filesystem .
Eli_B
9

По крайней мере, в Unix / Linux всегда безопасно соединять части пути /, даже если некоторые части пути уже оканчиваются /, т. root/pathЕ. Эквивалентны root//path.

В этом случае все, что вам действительно нужно, - это присоединиться к делу /. Тем не менее, я согласен с другими ответами, которые boost::filesystemявляются хорошим выбором, если они доступны вам, поскольку они поддерживают несколько платформ.

франк
источник
2
QT не зависит от разделителя путей. Если вы напечатаете абсолютный путь к файлу в Windows, вы получите «C: /Users/Name/MyFile.txt» с разделителем / (unix). boost :: filesystem - это здорово, но, на мой взгляд, если проект основан на Qt, нет необходимости добавлять зависимость для библиотеки boost.
LoSciamano,
7

Если вы хотите сделать это с помощью Qt, вы можете использовать QFileInfoконструктор:

QFileInfo fi( QDir("/tmp"), "file" );
QString path = fi.absoluteFilePath();
LoSciamano
источник
4

С C ++ 11 и Qt вы можете сделать это:

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

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

Применение:

QString path = join("/tmp", "dir", "file"); // /tmp/dir/file
Kainjow
источник
3

В Qt просто используйте /код при использовании Qt API ( QFile, QFileInfo). Он будет работать правильно на всех платформах. Если вам нужно передать путь к функции, отличной от Qt, или вы хотите отформатировать ее для отображения пользователю, используйте, QDir:toNativeSeparators()например:

QDir::toNativeSeparators( path );

Он будет заменен /собственным эквивалентом (например, \в Windows). Другое направление - через QDir::fromNativeSeparators().

Фрэнк Остерфельд
источник