2012-04-16 10 views
24

Welche Methoden der boost::filesystem Bibliothek kann mir helfen, einen Pfad relativ zu einem anderen Pfad zu erhalten?boost :: filesystem relative Pfad

Ich habe einen Pfad /home/user1/Downloads/Books und einen Pfad /home/user1/. Jetzt möchte ich einen Pfad Downloads/Books bekommen.

+0

Alles andere schlägt fehl, konvertieren Sie beide in absolute Zeichenfolgen und Teilzeichenfolge voneinander. –

+0

Neue Versionen von Boost haben eine ** sehr einfache ** Antwort darauf, vorausgesetzt [unten] (https://stackoverflow.com/a/37715252/16287) –

Antwort

14

von einem Link, indem Sie das Ticket Nicol verknüpft gefunden wurde:

template < > 
    path& path::append< typename path::iterator >(typename path::iterator begin, typename path::iterator end, const codecvt_type& cvt) 
    { 
     for(; begin != end ; ++begin) 
      *this /= *begin; 
     return *this; 
    } 
    // Return path when appended to a_From will resolve to same as a_To 
    boost::filesystem::path make_relative(boost::filesystem::path a_From, boost::filesystem::path a_To) 
    { 
     a_From = boost::filesystem::absolute(a_From); a_To = boost::filesystem::absolute(a_To); 
     boost::filesystem::path ret; 
     boost::filesystem::path::const_iterator itrFrom(a_From.begin()), itrTo(a_To.begin()); 
     // Find common base 
     for(boost::filesystem::path::const_iterator toEnd(a_To.end()), fromEnd(a_From.end()) ; itrFrom != fromEnd && itrTo != toEnd && *itrFrom == *itrTo; ++itrFrom, ++itrTo); 
     // Navigate backwards in directory to reach previously found base 
     for(boost::filesystem::path::const_iterator fromEnd(a_From.end()); itrFrom != fromEnd; ++itrFrom) 
     { 
      if((*itrFrom) != ".") 
       ret /= ".."; 
     } 
     // Now navigate down the directory branch 
     ret.append(itrTo, a_To.end()); 
     return ret; 
    } 

-Stick, die in einer Header-Datei und sollte es tun, was Sie wollen.

Beispielaufruf:

boost::filesystem::path a("foo/bar"), b("foo/test/korv.txt"); 
std::cout << make_relative(a, b).string() << std::endl; 
+1

Keine Notwendigkeit, 'make_relative' in diesem Beispiel-Aufruf zu qualifizieren. Es könnte falsch sein (der angegebene Code sieht nicht so aus, als würde 'make_relative' in' boost :: filesystem' gesetzt) ​​und wenn es richtig ist, ist es aufgrund von ADL unnötig. – MSalters

6

Leider existiert eine solche Funktion in Boost.Filesystem nicht. It has been requested, aber das scheint sie nicht zu kümmern.

Sie müssen es im Grunde manuell tun.

Boost.Filesystem 1.60 hinzugefügt the relative function, die verwendet werden können, um damit umzugehen.

+1

Eigentlich wurde der Patch aus einem Grund abgelehnt (Verwendung von anhängen). –

+1

@ MahmoudAl-Qudsi: Ich bin mit einer Feature-Anfrage verknüpft. In einem Kommentar zu dieser Anfrage ist ein Patch verknüpft, der jedoch nicht * Teil * der Anfrage ist. –

+0

Sie haben Recht. Vielleicht würden ein paar mehr Kommentare da helfen? :) –

1

Der Code der akzeptierte Antwort nicht funktioniert. Es sollte

sein
namespace boost { namespace filesystem { 

template <> path& path::append<path::iterator>(path::iterator begin, path::iterator end, const codecvt_type& cvt) 
{ 
    for(; begin != end ; ++begin) 
     *this /= *begin; 
    return *this; 
} 

// Return path when appended to a_From will resolve to same as a_To 
boost::filesystem::path make_relative(boost::filesystem::path a_From, boost::filesystem::path a_To) 
{ 
    a_From = boost::filesystem::absolute(a_From); a_To = boost::filesystem::absolute(a_To); 
    boost::filesystem::path ret; 
    boost::filesystem::path::const_iterator itrFrom(a_From.begin()), itrTo(a_To.begin()); 
    // Find common base 
    for(boost::filesystem::path::const_iterator toEnd(a_To.end()), fromEnd(a_From.end()) ; itrFrom != fromEnd && itrTo != toEnd && *itrFrom == *itrTo; ++itrFrom, ++itrTo); 
    // Navigate backwards in directory to reach previously found base 
    for(boost::filesystem::path::const_iterator fromEnd(a_From.end()); itrFrom != fromEnd; ++itrFrom) 
    { 
     if((*itrFrom) != ".") 
      ret /= ".."; 
    } 
    // Now navigate down the directory branch 
    ret.append(itrTo, a_To.end()); 
    return ret; 
} 

} } // namespace boost::filesystem 
17

Der Code in den bereitgestellten Antworten ist in jeder Zeile ziemlich lang. Unter der Annahme, dass Sie namespace fs = boost::filesystem; schrieb dann dieser Code bekommt man die meisten der Weg und sieht einfacher für mich zu lesen:

static fs::path relativeTo(fs::path from, fs::path to) 
{ 
    // Start at the root path and while they are the same then do nothing then when they first 
    // diverge take the entire from path, swap it with '..' segments, and then append the remainder of the to path. 
    fs::path::const_iterator fromIter = from.begin(); 
    fs::path::const_iterator toIter = to.begin(); 

    // Loop through both while they are the same to find nearest common directory 
    while (fromIter != from.end() && toIter != to.end() && (*toIter) == (*fromIter)) 
    { 
     ++toIter; 
     ++fromIter; 
    } 

    // Replace from path segments with '..' (from => nearest common directory) 
    fs::path finalPath; 
    while (fromIter != from.end()) 
    { 
     finalPath /= ".."; 
     ++fromIter; 
    } 

    // Append the remainder of the to path (nearest common directory => to) 
    while (toIter != to.end()) 
    { 
     finalPath /= *toIter; 
     ++toIter; 
    } 

    return finalPath; 
} 
+0

das funktionierte für mich –

+2

Das sieht so viel besser aus als die anderen Antworten. –

20

In neuen Versionen von boost (ab 1.60), können Sie boost::filesystem::relative verwenden. (See the documentation here.)

#include <boost/filesystem.hpp> 
#include <iostream> 
namespace fs = boost::filesystem; 

int main() 
{ 
    fs::path parentPath("/home/user1/"); 
    fs::path childPath("/home/user1/Downloads/Books"); 
    fs::path relativePath = fs::relative(childPath, parentPath); 
    std::cout << relativePath << std::endl; 
} 
Verwandte Themen