2012-04-16 340 views
24

boost::filesystem庫的哪些方法可以幫助我獲取相對於另一個路徑的路徑?boost :: filesystem獲取相對路徑

我有一個路徑/home/user1/Downloads/Books和路徑/home/user1/。現在我想要一條路徑Downloads/Books

+0

所有其他都失敗,將兩者都轉換爲絕對字符串和子字符串。 – 2012-04-16 00:33:25

+0

新版本的boost有一個非常簡單的**答案,提供[下面](https://stackoverflow.com/a/37715252/16287) – 2017-10-12 22:11:33

回答

14

從鏈接摘自以下尼科爾掛票發現:

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; 
+1

在該示例調用中不需要限定'make_relative'。它可能是錯誤的(給定的代碼看起來不像'make_relative'在'boost :: filesystem'中),如果它是正確的,由於ADL,它是沒有必要的。 – MSalters 2013-08-26 11:22:49

6

不幸的是,Boost.Filesystem中不存在這樣的函數。 It has been requested,但他們似乎並不在乎。

你基本上必須手動完成。

Boost.Filesystem 1.60增加了the relative function可以用來處理這個。

+1

實際上,該補丁被拒絕的原因(使用附加)。 – 2012-04-16 00:55:22

+1

@ MahmoudAl-Qudsi:我鏈接到一個功能請求。在該請求的評論中有一個補丁鏈接,但它不是請求的*部分*。 – 2012-04-16 01:09:56

+0

你說得對。也許還有更多的評論會有幫助? :) – 2012-04-16 01:49:12

1

接受的答案的代碼不起作用。它應該是

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

的代碼所提供的答案是相當長的,每行。假設你寫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; 
} 
+0

這工作對我來說 – 2015-10-09 14:33:05

+2

這看起來比其他答案好多了。 – 2015-12-26 18:52:31

20

boost新版本(在1.60開始),就可以使用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; 
}