Come costruire una stringa di percorso completo (in modo sicuro) da stringhe separate?


89

C ++ ha qualche equivalente alla funzione di Python os.path.join? Fondamentalmente, sto cercando qualcosa che combini due (o più) parti di un percorso di file in modo da non doverti preoccupare di assicurarti che le due parti si adattino perfettamente. Se è in Qt, anche quello sarebbe bello.

Fondamentalmente ho passato un'ora a eseguire il debug di un codice e almeno una parte era perché root + filenamedoveva esserlo root/ + filename, e sto cercando di evitarlo in futuro.


Possibilmente correlato alla lontana: stackoverflow.com/questions/5772992/… (in particolare, correlato a questa domanda è boost's complete)
Lightness Races in Orbit

Risposte:


44

Dai un'occhiata a QDir per questo:

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

3
Attenzione che Qt è GPL. Potrebbe essere un problema per molti usi.
rustyx

2
@RustyX è LGPL, per essere precisi.
Pa_

97

Solo come parte della libreria Boost.Filesystem . Ecco un esempio:

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

Ecco un esempio di compilazione ed esecuzione (specifico della piattaforma):

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

1
Questo è anche in TR2, che probabilmente inizierà la spedizione con i compilatori il prossimo anno.
ildjarn

1
@Vlad: Sì, non è facilmente individuabile, ma odio fare clic su Boost link ai documenti e accorgermi tardivamente che sto guardando una vecchia versione, quindi modifico i link specifici della versione delle persone quando li incontro. :-P
ildjarn

1
@ildjarn: che sembra funzionare alla grande ora ... ma aspetta finché non cambiano qualcosa sul sito o sui documenti per la libreria data. È peggio che lasciare il collegamento specifico della versione da quel momento in poi.
Fred Nurk

1
@Fred: Ovviamente se la funzionalità o la domanda è specifica della versione, non cambio l'URL. In questo caso, non lo è, quindi l'ho fatto.
ildjarn

1
@ildjarn: come prevedi cosa cambierà in futuro una data libreria in modo da poter sapere se tutte le risposte che modifichi avranno senso per tutte le versioni future?
Fred Nurk

24

Simile alla risposta di @ user405725 (ma non usando boost) e menzionata da @ildjarn in un commento, questa funzionalità è disponibile come parte di std :: filesystem . Il codice seguente viene compilato utilizzando Homebrew GCC 9.2.0_1 e utilizzando il 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;
}

4
A partire da C ++ 17, questo è stato unito all'intestazione (non sperimentale) <filesystem>. Vedi en.cppreference.com/w/cpp/filesystem .
Eli_B

9

Almeno in Unix / Linux, è sempre sicuro unire parti di un percorso per /, anche se alcune parti del percorso finiscono già con /, cioè root/pathè equivalente a root//path.

In questo caso, tutto ciò di cui hai veramente bisogno è unirti alle cose /. Detto questo, sono d'accordo con altre risposte che boost::filesystemè una buona scelta se è disponibile perché supporta più piattaforme.


2
QT è agnostico al separatore di percorso. Se si stampa il percorso assoluto di un file su Windows, l'output è "C: /Users/Name/MyFile.txt" con il separatore / (unix). boost :: filesystem è ottimo ma, secondo me, se il progetto è basato su Qt non è necessario aggiungere una dipendenza per la libreria boost.
LoSciamano

7

Se vuoi farlo con Qt, puoi usare il QFileInfocostruttore:

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

4

Con C ++ 11 e Qt puoi fare questo:

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

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

Utilizzo:

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

3

In Qt, usalo semplicemente /nel codice quando usi Qt API ( QFile, QFileInfo). Farà la cosa giusta su tutte le piattaforme. Se devi passare un percorso a una funzione non Qt, o vuoi formattarlo per visualizzarlo all'utente, usa QDir:toNativeSeparators()ad esempio:

QDir::toNativeSeparators( path );

Sostituirà /l'equivalente nativo (cioè \su Windows). L'altra direzione è fatta tramite QDir::fromNativeSeparators().

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.