Lig*_*ica 31 c++ boost boost-filesystem
我有两个绝对文件系统路径(A和B),我想生成第三个文件系统路径,表示"B的相对".
使用案例:
boost::filesystem
似乎必须complete
解决relative ~ relative => absolute
,但在reverse(absolute ~ absolute => relative
)中没有做任何事情.
我想用Boost路径来做.
Lig*_*ica 19
从版本1.60.0开始, boost.filesystem支持这一点.您正在寻找会员功能path lexically_relative(const path& p) const
.
原价,1.60.0以下的答案.
Boost不支持这个; 这是一个悬而未决的问题 - #1976(完全反向函数) - 但似乎没有太大的牵引力.
这是一个模糊的天真的解决方法,似乎可以解决这个问题(不确定它是否可以改进):
#include <boost/filesystem/path.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/fstream.hpp>
#include <stdexcept>
/**
* https://svn.boost.org/trac/boost/ticket/1976#comment:2
*
* "The idea: uncomplete(/foo/new, /foo/bar) => ../new
* The use case for this is any time you get a full path (from an open dialog, perhaps)
* and want to store a relative path so that the group of files can be moved to a different
* directory without breaking the paths. An IDE would be a simple example, so that the
* project file could be safely checked out of subversion."
*
* ALGORITHM:
* iterate path and base
* compare all elements so far of path and base
* whilst they are the same, no write to output
* when they change, or one runs out:
* write to output, ../ times the number of remaining elements in base
* write to output, the remaining elements in path
*/
boost::filesystem::path
naive_uncomplete(boost::filesystem::path const p, boost::filesystem::path const base) {
using boost::filesystem::path;
using boost::filesystem::dot;
using boost::filesystem::slash;
if (p == base)
return "./";
/*!! this breaks stuff if path is a filename rather than a directory,
which it most likely is... but then base shouldn't be a filename so... */
boost::filesystem::path from_path, from_base, output;
boost::filesystem::path::iterator path_it = p.begin(), path_end = p.end();
boost::filesystem::path::iterator base_it = base.begin(), base_end = base.end();
// check for emptiness
if ((path_it == path_end) || (base_it == base_end))
throw std::runtime_error("path or base was empty; couldn't generate relative path");
#ifdef WIN32
// drive letters are different; don't generate a relative path
if (*path_it != *base_it)
return p;
// now advance past drive letters; relative paths should only go up
// to the root of the drive and not past it
++path_it, ++base_it;
#endif
// Cache system-dependent dot, double-dot and slash strings
const std::string _dot = std::string(1, dot<path>::value);
const std::string _dots = std::string(2, dot<path>::value);
const std::string _sep = std::string(1, slash<path>::value);
// iterate over path and base
while (true) {
// compare all elements so far of path and base to find greatest common root;
// when elements of path and base differ, or run out:
if ((path_it == path_end) || (base_it == base_end) || (*path_it != *base_it)) {
// write to output, ../ times the number of remaining elements in base;
// this is how far we've had to come down the tree from base to get to the common root
for (; base_it != base_end; ++base_it) {
if (*base_it == _dot)
continue;
else if (*base_it == _sep)
continue;
output /= "../";
}
// write to output, the remaining elements in path;
// this is the path relative from the common root
boost::filesystem::path::iterator path_it_start = path_it;
for (; path_it != path_end; ++path_it) {
if (path_it != path_it_start)
output /= "/";
if (*path_it == _dot)
continue;
if (*path_it == _sep)
continue;
output /= *path_it;
}
break;
}
// add directory level to both paths and continue iteration
from_path /= path(*path_it);
from_base /= path(*base_it);
++path_it, ++base_it;
}
return output;
}
Run Code Online (Sandbox Code Playgroud)
我只是编写了可以将绝对路径转换为相对路径的代码.它适用于我的所有用例,但我不能保证它是完美的.
为了便于阅读,我将boost :: filesystem改为'fs'.在函数定义中,您可以使用fs :: path :: current_path()作为'relative_to'的默认值.
fs::path relativePath( const fs::path &path, const fs::path &relative_to )
{
// create absolute paths
fs::path p = fs::absolute(path);
fs::path r = fs::absolute(relative_to);
// if root paths are different, return absolute path
if( p.root_path() != r.root_path() )
return p;
// initialize relative path
fs::path result;
// find out where the two paths diverge
fs::path::const_iterator itr_path = p.begin();
fs::path::const_iterator itr_relative_to = r.begin();
while( itr_path != p.end() && itr_relative_to != r.end() && *itr_path == *itr_relative_to ) {
++itr_path;
++itr_relative_to;
}
// add "../" for each remaining token in relative_to
if( itr_relative_to != r.end() ) {
++itr_relative_to;
while( itr_relative_to != r.end() ) {
result /= "..";
++itr_relative_to;
}
}
// add remaining path
while( itr_path != p.end() ) {
result /= *itr_path;
++itr_path;
}
return result;
}
Run Code Online (Sandbox Code Playgroud)
我只是考虑使用boost::filesystem
相同的任务,但是 - 由于我的应用程序同时使用Qt和Boost库,我决定使用Qt,它使用一个简单的方法执行此任务:QString QDir :: relativeFilePath(const QString&fileName):
QDir dir("/home/bob");
QString s;
s = dir.relativeFilePath("images/file.jpg"); // s is "images/file.jpg"
s = dir.relativeFilePath("/home/mary/file.txt"); // s is "../mary/file.txt"
Run Code Online (Sandbox Code Playgroud)
它就像一个魅力,并为我节省了几个小时的生命.
使用C ++ 17及其std::filesystem::relative
从boost演变而来的,这是显而易见的:
#include <filesystem>
#include <iostream>
namespace fs = std::filesystem;
int main()
{
const fs::path base("/is/the/speed/of/light/absolute");
const fs::path p("/is/the/speed/of/light/absolute/or/is/it/relative/to/the/observer");
const fs::path p2("/little/light/races/in/orbit/of/a/rogue/planet");
std::cout << "Base is base: " << fs::relative(p, base).generic_string() << '\n'
<< "Base is deeper: " << fs::relative(base, p).generic_string() << '\n'
<< "Base is orthogonal: " << fs::relative(p2, base).generic_string();
// Omitting exception handling/error code usage for simplicity.
}
Run Code Online (Sandbox Code Playgroud)
输出(第二个参数为基数)
Base is base: or/is/it/relative/to/the/observer
Base is deeper: ../../../../../../..
Base is orthogonal: ../../../../../../little/light/races/in/orbit/of/a/rogue/planet
Run Code Online (Sandbox Code Playgroud)
它采用std::filesystem::path::lexically_relative
了比较。与纯词法函数的不同之处在于,它std::filesystem::relative
可以在比较之前使用std::filesystem::weakly_canonical
(为引入了relative
)解析符号链接并将两个路径归一化
。
归档时间: |
|
查看次数: |
17624 次 |
最近记录: |