boost::filesystem get relative path

后端 未结 5 2111
予麋鹿
予麋鹿 2020-12-29 20:20

What methods of the boost::filesystem library can help me to get a path relative to another path?

I have a path /home/user1/Downloads/Books

相关标签:
5条回答
  • 2020-12-29 20:30

    The accepted answer's code doesn't work. It should be

    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
    
    0 讨论(0)
  • 2020-12-29 20:48

    Taken from a link found by following the ticket Nicol linked to:

    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 that in a header file and it should do what you want.

    Sample call:

    boost::filesystem::path a("foo/bar"), b("foo/test/korv.txt");
    std::cout << make_relative( a, b ).string() << std::endl;
    
    0 讨论(0)
  • 2020-12-29 20:49

    Sadly, such a function does not exist in Boost.Filesystem. It has been requested, but they don't seem to care.

    You basically have to do it manually.

    Boost.Filesystem 1.60 added the relative function that can be used to handle this.

    0 讨论(0)
  • 2020-12-29 20:50

    The code in the provided answers is quite long on each line. Assuming that you wrote namespace fs = boost::filesystem; then this code gets you most of the way and looks easier to read to me:

        auto relativeTo( const fs::path& from, const 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.
           auto fromIter = from.begin();
           auto 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)
           auto finalPath = fs::path{};
           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 讨论(0)
  • 2020-12-29 20:52

    In new versions of boost (starting in 1.60), you can use 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;
    }
    
    0 讨论(0)
提交回复
热议问题