web-dev-qa-db-ja.com

boost :: filesystem相対パスを取得する

boost::filesystemライブラリのどのメソッドが、別のパスからの相対パスを取得するのに役立ちますか?

パス/home/user1/Downloads/Booksとパス/home/user1/があります。次に、パスDownloads/Booksを取得します。

29
itun

Nicolがリンクしているチケットをたどって見つかったリンクから取得:

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

それをヘッダーファイルに貼り付ければ、必要な処理が実行されます。

呼び出しの例:

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

boostの新しいバージョン(1.60以降)では、boost::filesystem::relativeを使用できます。 (こちらのドキュメントを参照してください。)

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

提供された回答のコードは、各行でかなり長くなっています。あなたが書いたと仮定するとnamespace fs = boost::filesystem;次に、このコードを使用すると、ほとんどの方法を理解でき、読みやすくなります。

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

残念ながら、そのような関数はBoost.Filesystemには存在しません。 リクエストされました 、しかし彼らは気にしていないようです。

基本的には手動で行う必要があります。

Boost.Filesystem 1.60が追加されました これを処理するために使用できるrelative関数

6
Nicol Bolas

承認された回答のコードが機能しません。そのはず

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
1
CyberSnoopy