为什么QFile无法从“~”目录读取?

6

我尝试了下面这个简短的例子,以找出我正在处理的一个大程序中的错误。看起来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文件访问的实现包括该扩展。

3
实现 operator/(QDir, std::string) 可能是值得的,这样你就可以写成 QDir::homePath()/".vimrc" - MSalters
抱歉,你是什么意思? - KcFnMi
4个回答

11

你可以创建一个助手函数来帮你完成这个操作,例如:

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上使用(根据代码中的评论)。我认为这对于此问题不是问题,因为 .vimrc 表示您运行的不是该平台(在Windows上是_vimrc)。

可以根据该平台进行调整,并且确实显示了辅助函数解决方案很适合,因为您只需更改一个代码片段即可添加该功能。


好的,你可以进行 pwent 查找或其他操作。作为一个快速解决方案,我选择使用 QString("%1/.vimrc").arg(QDir::homePath())。稍后我会研究更优雅的解决方案。也许有人会发布它。;-) - hurikhan77
1
@paxdiablo:虽然可以使用user来定义“user”的主目录,但与普通的相比,这种用法并不常见,后者用于指代自己的主目录。无论如何,您可以通过查找作为第一个字符,然后检查第二个字符是否为/来区分它们之间的差异。处理user会变得更加混乱...但是您至少可以检测到它并进行投诉 :) - David Rodríguez - dribeas
1
好的,我添加了一些(未经测试的)代码,应该可以处理其他用户。请记住它不是线程安全的,如果您需要,请使用 _r 版本。实际上,它可能甚至无法编译,但这是一个好的开始 :-) 在您使其工作后随意编辑(或让我知道问题,我会自己修复)。干杯。 - paxdiablo
1
如果用户在配置文件中输入“~foo/bar.baz”(或在对话框中输入;我过去曾经处理过这种情况),那么程序员就没有权利说“不要在其他人的主目录中胡乱搞”。让操作系统来处理这个问题,或者也许其他用户实际上已经授予了该文件的权限。当代码开始运行时,这种情况就会发生。 - Donal Fellows
这个问题并不是关于是否应该在其他用户目录中进行探索。在这种情况下,我需要它来在用户之间共享一些打印模板,其中一个用户可以在他的主目录中保留和编辑。然而,这不会是一个永久的解决方案,它将被后续替换。 - hurikhan77
显示剩余4条评论

3

这与不支持UNIX没有关系;波浪号扩展到用户的主目录是由shell执行的替换操作,因此,您需要手动替换它们。


是的,我知道这是一个shell扩展。但它非常方便,我希望unix Qt实现能够支持并扩展波浪号。 - hurikhan77

3

0

看一下C库函数glob,它可以进行波浪线扩展(可能还包括通配符扩展和其他各种功能)。


我想这将涉及到转义其他特殊的globbing字符,而我不想去处理它们。而且我必须以某种方式处理返回列表中的多个条目,因为glob不会返回单个字符串(尽管是包含可能只有一个字符串的列表)。 - hurikhan77
1
这取决于您的操作系统;例如,OS X具有GLOB_LIMIT标志,它将允许您仅请求一个结果。对于可能更有用的功能,请尝试使用wordexp,它可以让您执行大多数shell在构建命令方面所做的工作。 - Andrew McGregor

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接