【问题标题】:Why can't QFile read from the "~" directory?为什么QFile不能从“~”目录中读取?
【发布时间】:2011-02-18 11:29:13
【问题描述】:

我尝试了以下简短示例来找出我正在处理的更大程序中的错误。看起来 QFile 不支持主目录的 unix(或 shell 的)表示法:

#include <QFile>
#include <QDebug>

int main()
{
        QFile f("~/.vimrc");
        if (f.open(QIODevice::ReadOnly))
        {
                qDebug() << f.readAll();
                f.close();
        }
        else
        {
                qDebug() << f.error();
        }
}

只要我用我的真实主目录路径替换“~”,它就可以工作了。是否有一个简单的解决方法 - 启用一些设置?还是我必须走“丑陋”的方式,向 QDir 询问当前用户的主目录并手动将其添加到每个路径?

附录: 很明显,shell 通常会执行波浪号扩展,因此程序永远不会看到。它在 unix shell 中仍然非常方便,我希望用于文件访问的 Qt 实现能够包含该扩展。

【问题讨论】:

  • 可能值得实现operator/(QDir, std::string),这样你就可以写QDir::homePath()/".vimrc"

标签: c++ qt qt4 tilde-expansion qfile


【解决方案1】:

您可以创建一个辅助函数来为您执行此操作,例如:

QString morphFile(QString s) {
    if ((s == "~") || (s.startsWith("~/"))) {
        s.replace (0, 1, QDir::homePath());
    }
    return s;
}
:
QFile vimRc(morphFile("~/.vimrc"));
QFile homeDir(morphFile("~"));

一个更完整的解决方案,允许其他用户的主目录,可能是:

QString morphFile(QString fspec) {
    // Leave strings alone unless starting with tilde.

    if (! fspec.startsWith("~")) return fspec;

    // Special case for current user.

    if ((fspec == "~") || (fspec.startsWith("~/"))) {
        fspec.replace(0, 1, QDir::homePath());
        return fspec;
    }

    // General case for any user. Get user name and length of it.

    QString name (fspec);
    name.replace(0, 1, "");           // Remove leading '~'.
    int len = name.indexOf('/');      // Get name (up to first '/').
    len = (len == -1)
        ? name.length()
        : len - 1;
    name = name.left(idx);

    // Find that user in the password file, replace with home
    // directory if found, then return it. You can also add a
    // Windows-specific variant if needed.

    struct passwd *pwent = getpwnam(name.toAscii().constData());
    if (pwent != NULL)
        fspec.replace(0, len+1, pwent->pw_dir);

    return fspec;
}

请记住一件事,当前的解决方案不能移植到 Windows(根据代码中的 cmets)。我怀疑这对于直接的问题是可以的,因为.vimrc 表示这不是您正在运行的平台(它是 Windows 上的_vimrc)。

为该平台量身定制解决方案是可能的,并且确实表明辅助功能解决方案非常适合,因为您只需更改一个代码即可添加。 p>

【讨论】:

  • 虽然我喜欢这个想法,但在处理“~user”等情况时会变得很麻烦......
  • 你的代码可能不应该试图在另一个用户的目录中摆弄:-) 但是,是的,如果你想要完整的扩展,你可能需要去 shell抓住他们。我只是在回答您问题中的具体情况,即~。不过,如果您需要整个范围,那么仍然最好将代码隔离到这个单一的辅助函数。如果只是~/,请使用我提供的内容。如果是~&lt;anything-else&gt;,请在函数中找到另一种方式,例如运行子shell 来检索它的值。我看不出有一种不那么繁琐的方式来做你想做的事。
  • @paxdiablo:虽然 ~user 可用于定义“用户”的主目录,但它不像普通的 ~ 那样广泛使用来引用您自己的主目录。无论如何,您可以通过查找 ~ 作为第一个字符然后检查第二个字符是否是/不是来检测差异。与 ~user 打交道会变得更加混乱......但你至少可以检测到它并抱怨:)
  • 好的,我添加了一些(未经测试的)代码,它们也应该接近于处理其他用户。请记住,它不是线程安全的,如果需要,您需要使用 _r 版本。事实上,它甚至可能无法编译,但它是一个好的开始 :-) 一旦你让它工作,请随意编辑(或者让我知道问题,我会自己解决它们)。干杯。
  • @paxdiablo: 如果用户将~foo/bar.baz 放在配置文件中(或在对话框中输入;我过去曾处理过),那么这不是程序员的发言权“不要在其他人的主目录中摆弄”。把这句话留给操作系统,或者其他用户可能实际上已经授予了对该文件的权限。当代码落地时,就会发生这种事情。
【解决方案2】:

与不支持UNIX无关;波浪线到用户主目录的扩展是由 shell 执行的替换,所以是的,您必须手动替换它们。

【讨论】:

  • 是的,我知道这是一个外壳扩展。但它是如此方便,我希望 unix Qt 实现能够支持和扩展波浪号。
【解决方案3】:

请向 Qt bugtracker 提交建议。

https://bugreports.qt.io/

【讨论】:

    【解决方案4】:

    看看 C 库函数 glob,它会进行波浪号扩展(可能还有通配符扩展和各种其他函数)。

    【讨论】:

    • 我想这将涉及到排除其他特殊的 globbing 字符,然后我不想摆弄这些字符。而且我必须以某种方式处理返回列表中的多个条目,因为 glob 不会返回单个字符串(尽管列表可能只包含一个字符串)。
    • 这取决于你的操作系统;例如,OS X 有一个 GLOB_LIMIT 标志,它会让你只要求一个结果。对于更有用的功能,请尝试wordexp,它可以让您完成 shell 在构建命令时所做的大部分工作。
    猜你喜欢
    • 1970-01-01
    • 2014-07-22
    • 1970-01-01
    • 2014-09-18
    • 1970-01-01
    • 1970-01-01
    • 2011-04-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多