2012-04-16 8 views
24

¿Qué métodos de la biblioteca boost::filesystem pueden ayudarme a obtener una ruta relativa a otra ruta?boost :: filesystem get ruta relativa

Tengo una ruta /home/user1/Downloads/Books y una ruta /home/user1/. Ahora quiero obtener una ruta Downloads/Books.

+0

Todo lo demás falla, convierta ambos en cadenas absolutas y subcadenas una de la otra. –

+0

Las nuevas versiones de boost tienen una respuesta ** muy simple **, siempre que [abajo] (https://stackoverflow.com/a/37715252/16287) –

Respuesta

14

Tomado de un enlace que se encuentra siguiendo el billete Nicol vinculada a:

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 que en un archivo de cabecera y debe hacer lo que quiera.

llamada de ejemplo: Código

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

No es necesario calificar 'make_relative' en esa llamada de muestra. Puede ser incorrecto (el código dado no parece poner 'make_relative' en' boost :: filesystem') y si es correcto, no es necesario debido a ADL. – MSalters

6

Lamentablemente, dicha función no existe en Boost.Filesystem. It has been requested, pero parece que no les importa.

Básicamente tiene que hacerlo manualmente.

Boost.Filesystem 1.60 agregó the relative function que se pueden usar para manejar esto.

+1

En realidad, el parche fue rechazado por alguna razón (uso de adjuntar). –

+1

@ MahmoudAl-Qudsi: Me he vinculado a una solicitud de función. Hay un parche vinculado en un comentario sobre esa solicitud, pero no es * parte * de la solicitud. –

+0

Tienes razón. Tal vez algunos comentarios más allí ayudaría? :) –

1

del respuesta aceptada no funciona. Debe ser

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

El código en las respuestas proporcionadas es bastante largo en cada línea. Suponiendo que usted escribió namespace fs = boost::filesystem; entonces este código que obtiene la mayor parte del camino y se ve más fácil de leer para mí:

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

esto funcionó para mí –

+2

Esto se ve mucho mejor que las otras respuestas. –

20

En las nuevas versiones de boost (a partir de 1,60), puede utilizar boost::filesystem::relative. (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; 
} 
Cuestiones relacionadas