Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/wix/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何使用boost::filesystem“规范化”路径名?_C++_Boost_Filesystems - Fatal编程技术网

C++ 如何使用boost::filesystem“规范化”路径名?

C++ 如何使用boost::filesystem“规范化”路径名?,c++,boost,filesystems,C++,Boost,Filesystems,我们在应用程序中使用boost::filesystem。我有一个“完整”路径,它是通过将多个路径连接在一起构建的: #include <boost/filesystem/operations.hpp> #include <iostream>   namespace bf = boost::filesystem; int main() { bf::path root("c:\\some\\deep\\application\\folder"); b

我们在应用程序中使用boost::filesystem。我有一个“完整”路径,它是通过将多个路径连接在一起构建的:

#include <boost/filesystem/operations.hpp>
#include <iostream>
     
namespace bf = boost::filesystem;

int main()
{
    bf::path root("c:\\some\\deep\\application\\folder");
    bf::path subdir("..\\configuration\\instance");
    bf::path cfgfile("..\\instance\\myfile.cfg");

    bf::path final ( root / subdir / cfgfile);

    cout << final.file_string();
}
这是一个有效的路径,但是当我向用户显示它时,我希望它被规范化。注意:我甚至不确定normalized这个词是否正确。像这样:

c:\some\deep\application\configuration\instance\myfile.cfg
Boost的早期版本有一个normalize函数,但它似乎已被弃用,并在没有任何解释的情况下被删除


是否有理由不使用BOOST\u FILESYSTEM\u NO\u不推荐的宏?使用Boost文件系统库是否有其他方法可以做到这一点?或者我应该编写代码直接将路径作为字符串进行操作吗?

它仍然存在。继续使用它

我想他们不赞成它,因为符号链接意味着折叠路径不一定相等。如果c:\full\path是指向c:\rough的符号链接,则c:\full\path\。。将是c:\,而不是c:\完整。

解释如下:

在下面描述的现实中工作

理由:这不是一个研究项目。现在需要的是能够在当今平台上工作的东西,包括一些具有有限文件系统的嵌入式操作系统。由于强调可移植性,如果标准化,这样的库将更加有用。这意味着能够使用范围更广的平台,而这些平台仅限于Unix或Windows及其克隆

如果适用于消除正常化的现实是:

符号链接导致某些路径的规范和标准形式表示不同的文件或目录。例如,给定目录层次结构/a/b/c,在/a中有一个名为x的符号链接指向b/c,然后在POSIX路径名解析规则下,路径为/a/x/。。应解析为/a/b。如果/a/x/。。如果第一次规范化为/a,则将无法正确解析。箱子由沃尔特·兰德里提供

如果不访问底层文件系统,库就无法真正规范化路径,这使得操作不可靠、不可预测、错误,所有这些都是Boost v1.48及以上版本 您可以使用boost::filesystem::canonical:

v1.48及更高版本还提供了boost::filesystem::read_symlink函数,用于解析符号链接

v1.48之前的Boost版本 正如在其他答案中提到的,您不能正常化,因为boost::filesystem不能遵循符号链接。但是,您可以编写一个尽可能规范化的函数。和由于boost提供了确定文件是否为符号链接的能力,因此通常会对其进行处理

也就是说,如果。。是一个符号链接,那么你必须保留它,否则可能会安全地删除它,也可能总是安全地删除它

这类似于操纵实际字符串,但稍微优雅一些

boost::filesystem::path resolve(
    const boost::filesystem::path& p,
    const boost::filesystem::path& base = boost::filesystem::current_path())
{
    boost::filesystem::path abs_p = boost::filesystem::absolute(p,base);
    boost::filesystem::path result;
    for(boost::filesystem::path::iterator it=abs_p.begin();
        it!=abs_p.end();
        ++it)
    {
        if(*it == "..")
        {
            // /a/b/.. is not necessarily /a if b is a symbolic link
            if(boost::filesystem::is_symlink(result) )
                result /= *it;
            // /a/b/../.. is not /a/b/.. under most circumstances
            // We can end up with ..s in our result because of symbolic links
            else if(result.filename() == "..")
                result /= *it;
            // Otherwise it should be safe to resolve the parent
            else
                result = result.parent_path();
        }
        else if(*it == ".")
        {
            // Ignore
        }
        else
        {
            // Just cat other path entries
            result /= *it;
        }
    }
    return result;
}
对于boost::filesystem的版本3,您还可以通过调用canonical来尝试删除所有符号链接。这只能对现有路径执行,因此也适用于不存在路径的函数需要在MacOS Lion上测试两个步骤,并在Windows上更新@void.pointer的注释:

boost::filesystem::path normalize(const boost::filesystem::path &path) {
    boost::filesystem::path absPath = absolute(path);
    boost::filesystem::path::iterator it = absPath.begin();
    boost::filesystem::path result = *it++;

    // Get canonical version of the existing part
    for (; exists(result / *it) && it != absPath.end(); ++it) {
        result /= *it;
    }
    result = canonical(result);

    // For the rest remove ".." and "." in a path with no symlinks
    for (; it != absPath.end(); ++it) {
        // Just move back on ../
        if (*it == "..") {
            result = result.parent_path();
        }
        // Ignore "."
        else if (*it != ".") {
            // Just cat other path entries
            result /= *it;
        }
    }

    // Make sure the dir separators are correct even on Windows
    return result.make_preferred();
}

您对canonical的投诉和/或愿望已通过Boost 1.60[]和


由于规范函数仅适用于存在的路径,因此我制定了自己的解决方案,将路径拆分为各个部分,并将每个部分与下一部分进行比较。我用的是Boost 1.55

typedef boost::filesystem::path PathType;

template <template <typename T, typename = std::allocator<T> > class Container>
Container<PathType> SplitPath(const PathType& path)
{
    Container<PathType> ret;
    long the_size = std::distance(path.begin(),path.end());
    if(the_size == 0)
        return Container<PathType>();
    ret.resize(the_size);
    std::copy(path.begin(),path.end(),ret.begin());
    return ret;
}

PathType NormalizePath(const PathType& path)
{
    PathType ret;
    std::list<PathType> splitPath = SplitPath<std::list>(path);
    for(std::list<PathType>::iterator it = (path.is_absolute() ? ++splitPath.begin() : splitPath.begin()); it != splitPath.end(); ++it)
    {
        std::list<PathType>::iterator it_next = it;
        ++it_next;
        if(it_next == splitPath.end())
            break;
        if(*it_next == "..")
        {
            it = splitPath.erase(it);
            it = splitPath.erase(it);
        }
    }
    for(std::list<PathType>::iterator it = splitPath.begin(); it != splitPath.end(); ++it)
    {
        ret /= *it;
    }
    return ret;
}
要使用它,下面是一个关于如何称呼它的示例:

std::cout<<NormalizePath("/home/../home/thatfile/")<<std::endl;

我认为,希望这条道路正常化是理智、自然和预期的行为。看起来他们已经考虑过这个错误,并且在错误的.Boo.Fr.Script系统中犯了错误,这是因为它们包含在C++标准中,这就是为什么他们删除了一些平台上有用的特性。对于您所渴望的功能,已经有了一个事实上和事实上的标准,它在POSIX中的realpath:realpath函数将从file_name指向的路径名派生出一个绝对路径名,该路径名解析为相同的目录项,其解析不涉及“.”、“..”或符号链接cd/home/foo/tmp%ln-s foo..%echo$PWD/foo//home/foo/tmp/foo/。%realpath$PWD/foo//家/脚他那部分的象征性链接总是让我感到不安,这完全违反了最小惊讶的原则:/哪部分?AFAICS这部分就是符号链接的全部意义,不是吗?太糟糕了,有趣的是,声称这不是一个研究项目,然后很快就想出了一个让所有人都相信是的借口。当然,更好的解决方案是只在posix上实现realpath,以及windows上需要的任何东西,然后在不受支持的平台上抛出异常?抱歉,上面第4行中缺少了一个+。canonical仅适用于现有文件。我需要的东西也适用于nor使用的不存在的canonical路径
对路径的现有位进行恶意设置。这在Windows上不起作用。如果我传入E:\\foo\\.\\bar,我将返回E:/foo\\bar。斜杠不一致。将返回表达式更改为return result.make_preferred,这样就解决了问题。现在我得到了E:\\foo\\bar.@void.pointer,非常感谢。我曾经有机会在Windows上测试过这一点。在本例中,输入make_是首选。还要注意canonical在Windows链接和连接方面存在问题,至少在Boost 1.72中是这样。请注意,boost::filesystem::canonicalize需要一个路径,该路径实际上存在于文件系统中。因此,您不能使用它来规范化路径,该路径可能指向当前不存在的文件系统项,例如可移动介质或断开连接的网络驱动器上的路径。在这些情况下,函数将报告错误。与之相比,canonical在Windows链接和连接方面存在问题,至少在Boost 1.72中是这样。请参见弱规范和读取符号链接
path lexically_normal(const path& p);
typedef boost::filesystem::path PathType;

template <template <typename T, typename = std::allocator<T> > class Container>
Container<PathType> SplitPath(const PathType& path)
{
    Container<PathType> ret;
    long the_size = std::distance(path.begin(),path.end());
    if(the_size == 0)
        return Container<PathType>();
    ret.resize(the_size);
    std::copy(path.begin(),path.end(),ret.begin());
    return ret;
}

PathType NormalizePath(const PathType& path)
{
    PathType ret;
    std::list<PathType> splitPath = SplitPath<std::list>(path);
    for(std::list<PathType>::iterator it = (path.is_absolute() ? ++splitPath.begin() : splitPath.begin()); it != splitPath.end(); ++it)
    {
        std::list<PathType>::iterator it_next = it;
        ++it_next;
        if(it_next == splitPath.end())
            break;
        if(*it_next == "..")
        {
            it = splitPath.erase(it);
            it = splitPath.erase(it);
        }
    }
    for(std::list<PathType>::iterator it = splitPath.begin(); it != splitPath.end(); ++it)
    {
        ret /= *it;
    }
    return ret;
}
std::cout<<NormalizePath("/home/../home/thatfile/")<<std::endl;