【问题标题】:parent_path() with or without trailing slashparent_path() 带或不带斜杠
【发布时间】:2016-08-24 19:51:11
【问题描述】:

正如documentation 中所述,预期的输出如下:

boost::filesystem::path filePath1 = "/home/user/";
cout << filePath1.parent_path() << endl; // outputs "/home/user"

boost::filesystem::path filePath2 = "/home/user";
cout << filePath2.parent_path() << endl; // outputs "/home"

问题是,你如何处理这个问题?也就是说,如果我接受一个路径作为参数,我不希望用户关心它是否应该有一个斜杠。似乎最简单的做法是附加一个斜杠,然后调用parent_path() TWICE 以获取我想要的“/home”的父路径:

boost::filesystem::path filePath1 = "/home/user/";
filePath1 /= "/";
cout << filePath1.parent_path().parent_path() << endl; // outputs "/home"

boost::filesystem::path filePath2 = "/home/user";
filePath2 /= "/";
cout << filePath2.parent_path().parent_path() << endl; // outputs "/home"

但这似乎很荒谬。有没有更好的方法在框架内处理这个问题?

【问题讨论】:

    标签: c++ boost boost-filesystem


    【解决方案1】:

    有一个(未记录的?)成员函数:path&amp; path::remove_trailing_separator();

    我试过这个,它在 Windows 上使用 boost 1.60.0 对我有用:

    boost::filesystem::path filePath1 = "/home/user/";
    cout << filePath1.parent_path() << endl; // outputs "/home/user"
    cout << filePath1.remove_trailing_separator().parent_path() << endl; // outputs "/home"
    
    boost::filesystem::path filePath2 = "/home/user";
    cout << filePath2.parent_path() << endl; // outputs "/home"
    cout << filePath2.remove_trailing_separator().parent_path() << endl; // outputs "/home"
    

    【讨论】:

    • @Nacho 我们走了 :)
    • 有趣的是,这不处理多个尾随分隔符。即“/home/user//”.remove_trailing_separator().parent_path() 返回“/home/user”
    • 你可以使用filePath1.lexically_normal().remove_trailing_separator().parent_path(),但又开始看起来很奇怪..
    • 此外,在应用 remove_trailing_separator() 之前,可能需要对根路径进行额外检查。因为"/" 变成""(空路径),"d:/" 变成"d:",在某些情况下这并不是真正需要的。
    • 实际上,无论如何都可能需要检查,因为path("/").parent_path() 也给出了""
    【解决方案2】:

    您可以在 C++17 中使用 std::filesystem::canonical

    namespace fs = std::filesystem;
    
    fs::path tmp = "c:\\temp\\";
    
    tmp = fs::canonical(tmp); // will remove slash
    
    fs::path dir_name = tmp.filename(); // will get temp
    

    【讨论】:

    【解决方案3】:

    似乎是这样,尽管我建议对目录 string 进行先前的操作,而不是两次调用 parent_path()

    std::string directory = "/home/user"; // Try with "/home/user/" too, result is the same
    
    while ((directory.back() == '/') || (directory.back() == '\\')))
        directory.erase(directory.size()-1);    
    
    boost::filesystem::path filePath(directory);
    std::cout << filePath.parent_path() << std::endl; // outputs "/home" 
    

    请务必注意,std::string::back() 是 C++11 功能。如果您需要使用以前的版本进行编译,您将不得不稍微更改算法。

    【讨论】:

    • 那还是很手动的。如果您使用的是非 unix 系统,那么您还必须检查“\”。而且您可能还应该检查尾随'//'等。我在问 boost::filesystem 是否会有更像“justHandleItCorrectly(directory)”的东西:)
    • @DavidDoria 确实,在删除答案后,我重新考虑添加逻辑来处理您提到的情况,检查一下。
    • 当然,这仍然是完全有效的(但你能说总是吗?'\\\' 等呢),但我的观点是,这在我看来就像@987654325 的标准东西@ 通常擅长处理,但在此功能中似乎以非直观的方式失败。让每个人自己处理这件事似乎很愚蠢。通常在 Boost 中出现这种情况时,有人只是指出我错过的功能:)
    • @DavidDoria 现在是while,因此可以隐式考虑案例。我同意你的看法。你总是需要以/home 结尾还是只是一个例子?
    • 对不起,我没有注意到循环:),但我仍然想知道是否有人知道如何直接使用 boost::filesystem 处理这个问题。 /home/... 只是一个例子。
    【解决方案4】:

    要从指向目录的路径中删除尾随分隔符,到目前为止这对我有用:

    /**
     * Creates lexically normal (removes extra path separators and dots) directory
     * path without trailing path separator slash(es)
     * @param dir_path - directory path to normalize
     */
    void normalize_dir_path(boost::filesystem::path& dir_path) {
        // @HACK - append non-existing file to path so that we may later resolve
        // normalized directory path using parent_path()
        dir_path /= "FILE.TXT";
        // Remove unneeded dots and slashes
        dir_path = dir_path.lexically_normal();
        // Remove trailing slash from original path!
        dir_path = dir_path.parent_path();
    }
    

    上述答案类似于 OP 最初发布的解决方法(添加 '/')以及 Wurmloch 关于使用 lexically_normal() 的评论。一个优点是只使用来自boost::filesystem 的记录方法。一个可能的缺点是调用者必须确信输入参数dir_path 是一个目录而不是常规文件。

    使用normalize_dir_path(...)方法回答OP的问题:

    boost::filesystem::path filePath1 = "/home/user/";
    normalize_dir_path(filePath1); // filePath1 is now "/home/user"
    cout << filePath1.parent_path() << endl; // outputs "/home"
    
    boost::filesystem::path filePath2 = "/home/user";
    normalize_dir_path(filePath2); // filePath2 is now "/home/user"
    cout << filePath2.parent_path() << endl; // outputs "/home"
    
    boost::filesystem::path filePath3 = "/home/user/.";
    normalize_dir_path(filePath3); // filePath3 is now "/home/user"
    cout << filePath3.parent_path() << endl; // outputs "/home"
    

    更新

    刚刚意识到boost::filesystem::path::lexically_normal() 仅适用于 BOOST 版本 >= 1_60_0。对于早期版本,默认情况下似乎有一个已弃用的函数boost::filesystem::path::normalize()(只要未定义BOOST_FILESYSTEM_NO_DEPRECATED)。所以,我目前的规范化目录路径方法是这样的:

    #include <boost/version.hpp>
    
    void normalize_dir_path(boost::filesystem::path& dir_path) {
        // @HACK - append non-existing file to path so that we may later resolve
        // normalized directory path using parent_path()
        dir_path /= "FILE.TXT";
        // Remove unneeded dots and slashes
    #if BOOST_VERSION >= 106000
        dir_path = dir_path.lexically_normal();
    #else
        dir_path.normalize();
    #endif
        // Remove trailing slash from original path!
        dir_path = dir_path.parent_path();
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-08-24
      • 1970-01-01
      • 2019-01-26
      • 2016-04-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多