Comment créer une chaîne de chemin complet (en toute sécurité) à partir de chaînes séparées?

89

Le C ++ a-t-il un équivalent à la fonction de python os.path.join? Fondamentalement, je recherche quelque chose qui combine deux (ou plus) parties d'un chemin de fichier afin que vous n'ayez pas à vous soucier de vous assurer que les deux parties s'emboîtent parfaitement. Si c'est dans Qt, ce serait cool aussi.

En gros, j'ai passé une heure à déboguer du code et au moins une partie de cela était root + filenamedû au fait que cela devait être root/ + filename, et je cherche à éviter cela à l'avenir.

sas4740
la source
Peut-être lointainement lié: stackoverflow.com/questions/5772992/… (spécifiquement, lié à cette question est boost's complete)
Lightness Races in Orbit

Réponses:

44

Découvrez QDir pour cela:

QString path = QDir(dirPath).filePath(fileName);
Stephen Chu
la source
3
Attention, Qt est GPL. Peut être un facteur décisif pour de nombreuses utilisations.
rustyx
2
@RustyX c'est LGPL, pour être précis.
Pa_
97

Uniquement dans le cadre de la bibliothèque Boost.Filesystem . Voici un exemple:

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

Voici un exemple de compilation et d'exécution (spécifique à la plateforme):

$ g++ ./test.cpp -o test -lboost_filesystem -lboost_system
$ ./test 
/tmp/foo.txt
Azeem
la source
1
C'est également dans TR2, qui devrait commencer à être expédié avec les compilateurs l'année prochaine.
ildjarn
1
@Vlad: Oui, ce n'est pas facilement découvrable, mais je déteste cliquer sur les liens Boost doc et me rendre compte tardivement que je regarde une ancienne version, alors j'édite les liens spécifiques à la version des gens quand je les rencontre. :-P
ildjarn
1
@ildjarn: Ce qui semble fonctionner très bien maintenant ... mais attendez qu'ils changent quelque chose au sujet du site ou de la documentation pour la bibliothèque donnée. C'est pire que de quitter le lien spécifique à la version à partir de là.
Fred Nurk
1
@Fred: Évidemment, si la fonctionnalité ou la question est spécifique à la version, je ne change pas l'URL. Dans ce cas, ce n'est pas le cas, alors je l'ai fait.
ildjarn
1
@ildjarn: Comment prédisez-vous ce qu'une bibliothèque donnée va changer à l'avenir afin que vous puissiez savoir si toutes les réponses que vous éditez auront du sens pour toutes les versions futures?
Fred Nurk
24

Similaire à la réponse de @ user405725 (mais n'utilisant pas boost), et mentionnée par @ildjarn dans un commentaire, cette fonctionnalité est disponible dans le cadre de std :: filesystem . Le code suivant se compile en utilisant Homebrew GCC 9.2.0_1 et en utilisant l'indicateur --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
la source
4
À partir de C ++ 17, cela a été fusionné dans l'en-tête (non expérimental) <filesystem>. Voir en.cppreference.com/w/cpp/filesystem .
Eli_B
9

Au moins sous Unix / Linux, il est toujours sûr de joindre des parties d'un chemin /, même si certaines parties du chemin se terminent déjà par /, c'est root/path-à- dire équivalent à root//path.

Dans ce cas, tout ce dont vous avez vraiment besoin est de joindre les choses /. Cela dit, je suis d'accord avec d'autres réponses qui boost::filesystemsont un bon choix si elles sont disponibles car elles prennent en charge plusieurs plates-formes.

Frankc
la source
2
QT est indépendant du séparateur de chemin. Si vous imprimez le chemin absolu d'un fichier sous Windows, la sortie est "C: /Users/Name/MyFile.txt" avec le séparateur / (unix). boost :: filesystem est génial mais, à mon avis, si le projet est basé sur Qt, il n'est pas nécessaire d'ajouter une dépendance pour la bibliothèque boost.
LoSciamano le
7

Si vous voulez faire cela avec Qt, vous pouvez utiliser le QFileInfoconstructeur:

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

Avec C ++ 11 et Qt, vous pouvez faire ceci:

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
Kainjow
la source
3

Dans Qt, utilisez simplement /dans le code lorsque vous utilisez l'API Qt ( QFile, QFileInfo). Il fera ce qu'il faut sur toutes les plateformes. Si vous devez passer un chemin vers une fonction non-Qt, ou souhaitez le formater pour l'afficher à l'utilisateur, utilisez QDir:toNativeSeparators()par exemple:

QDir::toNativeSeparators( path );

Il remplacera /par l'équivalent natif (c'est- \à- dire sous Windows). L'autre sens se fait via QDir::fromNativeSeparators().

Frank Osterfeld
la source