Obtenez chemin relatif à partir de deux chemins absolus
J'ai deux absolus système de fichiers chemins (A et B), et je veux générer un troisième chemin du système de fichiers, qui représente "Un parent de B".
Cas d'utilisation:
- Media player de la gestion d'une liste de lecture.
- Utilisateur ajoute un fichier à la liste de lecture.
- Nouveau chemin d'accès au fichier ajouté à la liste de lecture par rapport à la sélection de chemin d'accès.
- Dans l'avenir, l'ensemble du répertoire de musique (y compris la liste de lecture) déplacé ailleurs.
- Tous les chemins encore valide, car ils sont relatifs à la liste de lecture.
boost::filesystem
semble avoir complete
pour résoudre relative ~ relative => absolute
, mais rien à faire cela dans le sens inverse (absolute ~ absolute => relative
).
Je veux le faire avec Boost chemins.
- Fortement liés (mais, de l'OMI, plus complet qu') stackoverflow.com/questions/5694700/...
- Un couple de plus liée (mais pas identique) questions: stackoverflow.com/questions/275689/... et stackoverflow.com/questions/2564634/.... Ils sont exprimés en termes de .NET et shell, respectivement, mais sont demander les mêmes fonctionnalités de base. Les réponses peuvent aider...
- Double Possible de Comment obtenir le chemin d'accès relatif de chemin absolu
- Cette question est au sujet d'une technologie entièrement différente....
Vous devez vous connecter pour publier un commentaire.
De la version 1.60.0 coup de pouce.système de fichiers prend en charge cette. Vous êtes à la recherche pour la fonction de membre
path lexically_relative(const path& p) const
.D'origine, pré-1.60.0 réponse ci-dessous.
Boost ne prend pas en charge ce; c'est une question ouverte — #1976 (fonction Inverse pour terminer) — qui, néanmoins, ne semble pas obtenir beaucoup de traction.
Voici un vaguement naïf solution qui semble faire l'affaire (pas sûr si elle peut être améliorée):
dot
etslash
ont été supprimés dans la v3 alors j'aimerais comprendre pourquoi, et j'aimerais savoir ce mécanisme abstrait doit les remplacer.Je viens d'écrire du code qui peut traduire un chemin absolu vers un chemin d'accès relatif. Il fonctionne dans tous mes cas d'utilisation, mais je ne peux pas garantir qu'il est impeccable.
J'ai abreviated boost::filesystem à " fs " pour des raisons de lisibilité. Dans la définition de la fonction, vous pouvez utiliser sf::chemin d'accès::current_path() comme valeur par défaut pour 'relative_to'.
relativePath()
sorties dans certaines situations parce que l'un des {itr_path
,itr_relative_to
} itérateurs peuvent déjà être égale à leur.end()
. La comparaison*itr_path==*itr_relative_to
n'est pas possible dans ce cas. Le déplacement de la comparaison après la... != .end()
vérifie résout ce problème.Je viens de penser à l'aide de
boost::filesystem
pour la même tâche, mais depuis mon application utilise Qt et bibliothèques Boost, j'ai décidé d'utiliser Qt qui ne de cette tâche avec une méthode simple QString QDir::relativeFilePath( const QString & fileName ):Il fonctionne comme un charme et m'a sauvé quelques heures de ma vie.
Avec C++17 et son
std::filesystem::relative
, qui a évolué à partir de boost, c'est un no-brainer:De sortie (deuxième paramètre est la base)
Il utilise
std::filesystem::chemin d'accès::lexically_relative
à des fins de comparaison.La différence la plus pure fonction lexicale est, que
std::filesystem::relative
résout les liens symboliques et normalise les deux chemins à l'aide destd::filesystem::weakly_canonical
(qui a été introduit pourrelative
) avant la comparaison.Voici comment je le fais dans la bibliothèque-je construire sur le dessus de boost, système de fichiers:
Étape 1: Déterminer "la plus profonde racine commune". Fondamentalement, c'est comme le plus grand dénominateur commun pour les 2 chemins. Par exemple, si vous êtes 2 chemins sont "C:\a\b\c\d" et "C:\a\b\c\l.txt" puis la racine commune qu'ils partagent est "C:\a\b\c\".
Pour l'obtenir, convertir les deux chemins en absolu - NON canonique de la forme (vous aurez envie d'être capable de faire cela à des fins de spéculation chemins & liens symboliques).
Étape 2: pour aller de A À B, vous suffixe Un avec suffisamment de copies de "../" pour déplacer vers le haut de l'arborescence du répertoire à la racine commune, puis ajouter la chaîne pour B de descendre de l'arbre. Sur windows, vous pouvez avoir 2 voies avec pas de racine commune, afin d'aller de A à aucun B n'est pas toujours possible.
}
Cela va faire ce que vous voulez - vous aller de Un jusqu'à ce que vous frappez le dossier commun et B sont tous deux des descendants de, puis allez vers le bas à un point B. Vous n'avez probablement pas besoin de la "commonDirsInOrder" retour que j'ai, mais le "routeFrom1To2" retour EST celui que vous demandez.
Si vous prévoyez de changer le répertoire de travail "B", vous pouvez utiliser "routeFrom1To2" directement. Sachez que cette fonction produit un chemin d'accès absolu en dépit de toutes les ".." de pièces, mais cela ne devrait pas être un problème.
J'avais besoin de faire cela sans Boost et les autres mst en fonction de la solution de ne pas le faire pour moi, donc j'ai ré-implémenté. J'ai travaillé sur cela, j'ai réalisé que je l'avais fait avant de trop...
De toute façon, il n'est pas aussi complet que certains des autres, mais qui pourrait être utile aux gens. C'est spécifique à Windows; changements pour le rendre POSIX impliquer séparateur de répertoire et de la casse de la chaîne de comparer.
Peu de temps après j'ai eu cette mise en œuvre et de travail que j'ai eu à transférer les environs de la fonctionnalité de Python donc, tout cela juste cuit à
os.path.relpath(to, from)
.Je dois écrire une solution simple pour cette astuce.
Il n'y a pas d'utilisation sur les bibliothèques boost, seulement STL
std::string
,std::vector
.La plate-forme Win32 a été testé.
Juste appeler:
Et, il serait de retour chemin relatif à partir de
PathA
àPathB
.Exemple: