Jak zbudować ciąg pełnej ścieżki (bezpiecznie) z oddzielnych ciągów?

91

Czy C ++ ma odpowiednik funkcji Pythona os.path.join? Zasadniczo szukam czegoś, co łączy dwie (lub więcej) części ścieżki pliku, abyś nie musiał się martwić, że te dwie części idealnie do siebie pasują. Jeśli jest w Qt, to też byłoby fajne.

Zasadniczo spędziłem godzinę na debugowaniu jakiegoś kodu, a przynajmniej część z tego była root + filenametaka root/ + filename, ponieważ musiała , i chcę tego uniknąć w przyszłości.

sas4740
źródło
Prawdopodobnie odlegle powiązane: stackoverflow.com/questions/5772992/… (konkretnie, związane z tym pytaniem to boosty complete)
Lightness Races in Orbit

Odpowiedzi:

45

Sprawdź QDir dla tego:

QString path = QDir(dirPath).filePath(fileName);
Stephen Chu
źródło
3
Uważaj, Qt jest na licencji GPL. Może być przełomem w wielu zastosowaniach.
rustyx
4
@RustyX to jest LGPL, żeby być precyzyjnym.
Pa_
99

Tylko jako część biblioteki Boost.Filesystem . Oto przykład:

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

Oto przykład kompilacji i uruchomienia (zależnie od platformy):

$ g++ ./test.cpp -o test -lboost_filesystem -lboost_system
$ ./test 
/tmp/foo.txt
Azeem
źródło
1
Dzieje się tak również w TR2, który prawdopodobnie rozpocznie wysyłkę z kompilatorami w przyszłym roku.
ildjarn
1
@Vlad: Tak, nie jest to łatwe do znalezienia, ale nienawidzę klikać linków do dokumentów Boost i z opóźnieniem zdaję sobie sprawę, że patrzę na starą wersję, więc edytuję linki specyficzne dla wersji, gdy je spotykam. :-P
ildjarn
1
@ildjarn: Co wydaje się teraz działać świetnie ... ale poczekaj, aż coś zmienią w witrynie lub dokumentach dla danej biblioteki. Jest to gorsze niż pozostawienie od tej pory linku specyficznego dla wersji.
Fred Nurk
1
@Fred: Oczywiście, jeśli funkcja lub pytanie dotyczy konkretnej wersji, nie zmieniam adresu URL. W tym przypadku tak nie jest, więc tak zrobiłem.
ildjarn
1
@ildjarn: Jak przewidujesz, co dana biblioteka zmieni się w przyszłości, abyś wiedział, czy wszystkie edytowane odpowiedzi będą miały sens we wszystkich przyszłych wersjach?
Fred Nurk
24

Podobnie jak odpowiedź @ user405725 (ale nie używająca boost) i wspomniana przez @ildjarn w komentarzu, ta funkcjonalność jest dostępna jako część systemu plików std :: . Poniższy kod kompiluje się przy użyciu Homebrew GCC 9.2.0_1 i przy użyciu flagi --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;
}
Shawn Blakesley
źródło
4
Począwszy od C ++ 17, zostało to scalone z (nieeksperymentalnym) nagłówkiem <filesystem>. Zobacz en.cppreference.com/w/cpp/filesystem .
Eli_B,
9

Przynajmniej w systemie Unix / Linux zawsze można bezpiecznie łączyć części ścieżki /, nawet jeśli niektóre części ścieżki już się kończą /, tj. root/pathSą równoważne root//path.

W takim przypadku wszystko, czego naprawdę potrzebujesz, to dołączyć do rzeczy /. To powiedziawszy, zgadzam się z innymi odpowiedziami, które boost::filesystemsą dobrym wyborem, jeśli są dostępne, ponieważ obsługują wiele platform.

frankc
źródło
2
QT jest niezależny od separatora ścieżek. Jeśli drukujesz bezwzględną ścieżkę do pliku w systemie Windows, wynikiem jest „C: /Users/Name/MyFile.txt” z separatorem / (unix). boost :: filesystem jest świetny, ale moim zdaniem, jeśli projekt jest oparty na Qt, nie ma potrzeby dodawania zależności dla biblioteki boost.
LoSciamano
7

Jeśli chcesz to zrobić z Qt, możesz użyć QFileInfokonstruktora:

QFileInfo fi( QDir("/tmp"), "file" );
QString path = fi.absoluteFilePath();
LoSciamano
źródło
4

Z C ++ 11 i Qt możesz to zrobić:

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

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

Stosowanie:

QString path = join("/tmp", "dir", "file"); // /tmp/dir/file
kainjow
źródło
3

W Qt po prostu użyj /w kodzie, gdy używasz Qt API ( QFile, QFileInfo). Będzie działać dobrze na wszystkich platformach. Jeśli musisz podać ścieżkę do funkcji innej niż Qt lub chcesz ją sformatować w celu wyświetlenia jej użytkownikowi, użyj QDir:toNativeSeparators()np .:

QDir::toNativeSeparators( path );

Zastąpi /natywny odpowiednik (np. W \systemie Windows). Drugi kierunek odbywa się za pośrednictwem QDir::fromNativeSeparators().

Frank Osterfeld
źródło