【问题标题】:How to compare (directory) paths in c++?如何在 C++ 中比较(目录)路径?
【发布时间】:2012-01-20 05:35:20
【问题描述】:

我正在寻找一种方法来检查 2 个字符串在文件系统路径(目录)方面是否相同。例如,这个集合中的所有字符串在文件系统路径方面都是相同的:{/x,\x,//x,/x/},但这两个 - /x/y 不是,即使/y/x 的符号链接。我要编写的程序应该适用于 Linux 以及 windows,所以我正在寻找可移植的解决方案。

编辑:

我只使用 boost 的仅标头库,因此boost::filesystem 的解决方案对我来说不合适。我知道windows API里面有UrlCompare,linux里面有类似的吗?

【问题讨论】:

  • +1 好问题。有没有提升的替代品?
  • 你现在使用的是header-only boost,但为什么这是不添加lib依赖的理由呢?
  • @Tomalak Garet'kal:因为在 Sun Studio 5.7 中编译 boost 存在一些问题
  • @MihranHovsepyan:听起来是个好理由。 :) 谢谢

标签: c++ path comparison cross-platform


【解决方案1】:
std::string path1 = "c:\\folder\\";
std::string path2 = "c:\\folder\\folder\\..\\";

boost::filesystem::equivalent(boost::filesystem::path(path1), boost::filesystem::path(path2)

代码返回true,因为文件夹其实是一样的。

【讨论】:

  • OP 说“所以使用 boost::filesystem 的解决方案对我来说不合适”。寻找替代品。
【解决方案2】:

任何非 Boost 解决方案都将涉及系统相关代码(即 如果使用 Boost,则隐藏在 Boost 中)。你必须准确定义 你所说的“匹配”是什么意思:应该"./MyFile.xxx""MyFile.xxx" 比较相等? "aaa/.../MyFile.xxx""MyFile.xxx" 呢?

我处理这个问题的方法是定义一个有两个数据成员的类, 带有“前缀”的std::string(始终是 在 Unix 中为空),以及带有所有路径的 std::vector<std::string> 元素。这门课会被必要的比较所宠爱 功能,并会使用系统相关的代码来实现 构造函数;构造函数本身将在源文件中,并且 源文件将包含与机器相关的标头(通常通过使用 每个变体都有一个单独的目录,并通过手段选择标题 -I/I 指定要使用的目录)。那种东西 这可能会进入标题:

inline bool
isPathSeparator( char ch )
{
    return ch == '/';
}

std::string
getHeader( std::string const& fullPathName )
{
    return "";
}

bool
charCompare( char lhs, char rhs )
{
    return lhs < rhs;
}

bool
charMatch( char lhs, char rhs )
{
    return lhs == rhs;
}

对于 Unix,带有:

inline bool
isPathSeparator( char ch )
{
    return ch == '/' || ch == '\\';
}

std::string
getHeader( std::string const& fullPathName )
{
    return fullPathName.size() > 2 && fullPathName[1] == ':'
        ? fullPathName.substr( 0, 2 )
        : std::string();
}

bool
charCompare( char lhs, char rhs )
{
    return tolower( (unsigned char)lhs) < tolower( (unsigned char)rhs );
}

bool
charMatch( char lhs, char rhs )
{
    return tolower( (unsigned char)lhs ) == tolower( (unsigned char)rhs );
}

适用于 Windows。

然后构造函数将使用getHeader 来初始化标头,并且 遍历input.begin() + header.size()input.end(),打破 串成元素。如果遇到"."的元素, 忽略它,对于".." 之一,使用pop_back() 删除顶部 路径的元素,前提是路径不为空。之后就是 只是定义比较器以使用charComparecharMatch 代表 charstd::lexicographical_comparestd::equal(在验证大小相等后)与 std::string 的比较器(可能还有你的新 班级)。比如:

struct FileNameCompare
{
    bool operator()( char lhs, char rhs ) const
    {
        return charCompare( lhs, rhs );
    }
    bool operator()( std::string const& lhs, std::string const& rhs ) const
    {
        return std::lexicographical_compare(
            lhs.begin(), lhs.end(),
            rhs.begin(), rhs.end(),
            *this );
    }
    bool operator()( FileName const& lhs, FileName const& rhs ) const
    {
        return (*this)( lhs.prefix, rhs.prefix )
            || ( !(*this)( rhs.prefix, lhs.prefix )
                && std::lexicographical_compare(
                    lhs.elements.begin(), lhs.elements.end(),
                    rhs.elements.begin(), rhs.elements.end(),
                    *this ) );
    }
};

struct FileNameMatch
{
    bool operator()( char lhs, char rhs ) const
    {
        return charMatch( lhs, rhs );
    }
    bool operator()( std::string const& lhs, std::string const& rhs ) const
    {
        return lhs.size() == rhs.size()
            && std::equal( lhs.begin(), lhs.end(), rhs.begin(), *this );
    }
    bool operator()( FileName const& lhs, FileName const& rhs ) const
    {
        return (*this)( lhs.prefix, rhs.prefix )
            && lhs.elements.size() == rhs.elements.size()
            && std::equal( lhs.elements.begin(), lhs.elements.end(),
                           rhs.elements.begin(),
                           *this );
    }
};

应该可以解决问题。 (请记住 operator()( char, char ) const 必须在源文件中;您不能将它们内联在标题中, 它不包括定义的系统相关标头 charComparecharMatch.)

【讨论】:

    【解决方案3】:

    使用boost::filesystem 库 - 它具有路径比较功能。

    编辑:您可以尝试apr - 是的,它不是 C++,但它是可移植的。

    【讨论】:

      【解决方案4】:

      在可移植性方面,Boost 文件系统库可能很有用 (documentation link)。更具体地说:path.hpp 最有用,您可以在其中使用路径比较。

      编辑

      This gmane.org 上的讨论涉及boost::filesystem 的最小标头版本。总结:这不存在。因此,您最终将构建自己的抽象库并为其提供跨平台功能。

      在 Linux 下,dirent.h 是一个 POSIX C 库。对于 Windows,您必须使用 Win32 API。但是,还有一个所谓的“Directory-Stream 库”,它似乎是跨平台的,可用here(网站为德语)。

      【讨论】:

        猜你喜欢
        • 2011-01-17
        • 2011-11-01
        • 2014-01-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多