我如何“规范化"?使用 boost::filesystem 的路径名?

2021-12-24 00:00:00 filesystems c++ boost

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

We are using boost::filesystem in our application. I have a 'full' path that is constructed by concatenating several paths together:

#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();
}

最终路径打印为:

c:somedeepapplicationfolder..configurationinstance..instancemyfile.cfg

这是一个有效的路径,但是当我向用户显示它时,我希望它被规范化.(注意:我什至不确定规范化"是否是正确的词为了这).像这样:

This is a valid path, but when I display it to the user I'd prefer it to be normalized. (Note: I'm not even sure if "normalized" is the correct word for this). Like this:

c:somedeepapplicationconfigurationinstancemyfile.cfg

早期版本的 Boost 有一个 normalize() 函数 - 但它似乎已被弃用和删除(没有任何解释).

Earlier versions of Boost had a normalize() function - but it seems to have been deprecated and removed (without any explanation).

我是否有理由不使用 BOOST_FILESYSTEM_NO_DEPRECATED 宏?有没有其他方法可以使用 Boost 文件系统库来做到这一点?还是应该写代码直接把路径作为字符串操作?

Is there a reason I should not use the BOOST_FILESYSTEM_NO_DEPRECATED macro? Is there an alternative way to do this with the Boost Filesystem library? Or should I write code to directly manipulating the path as a string?

推荐答案

Boost v1.48 及以上

你可以使用 boost::filesystem::canonical:

path canonical(const path& p, const path& base = current_path());
path canonical(const path& p, system::error_code& ec);
path canonical(const path& p, const path& base, system::error_code& ec);

http://www.boost.org/doc/libs/1_48_0/libs/filesystem/v3/doc/reference.html#canonical

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

v1.48 and above also provide the boost::filesystem::read_symlink function for resolving symbolic links.

正如其他答案中提到的,您无法标准化,因为 boost::filesystem 无法遵循符号链接.但是,您可以编写一个尽可能多地"规范化的函数(假设."和.."被正常处理),因为 boost 提供了确定文件是否为符号链接的能力.

As mentioned in other answers, you can't normalise because boost::filesystem can't follow symbolic links. However, you can write a function that normalises "as much as possible" (assuming "." and ".." are treated normally) because boost offers the ability to determine whether or not a file is a symbolic link.

也就是说,如果.."的父级是一个符号链接,那么你必须保留它,否则删除它可能是安全的,而删除."可能总是安全的.

That is to say, if the parent of the ".." is a symbolic link then you have to retain it, otherwise it is probably safe to drop it and it's probably always safe to remove ".".

它类似于操作实际的字符串,但稍微优雅一些??.

It's similar to manipulating the actual string, but slightly more elegant.

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

相关文章