前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >关于QProcess不能带空格的目录或文件

关于QProcess不能带空格的目录或文件

作者头像
Qt君
发布2019-07-16 15:19:26
3.2K0
发布2019-07-16 15:19:26
举报

在Window系统下使用QProcess的start单独运行一个程序时。当程序路径存在空格会运行不成功的现象,最诡异的是,有时又可以运行。这到底是为什么呢?本文将以源码实现的角度来分析到底是为何?

1. 问题重现

  • 下列运行Test Demo.exe将会提示"系统找不到指定的文件。"
QProcess process;
process.start("C:/Users/Tmp/Test Demo.exe");

2. 解决方案

  • 解决调用程序不能带有空格的问题。

2.1 使用使用空参数(arguments)的start接口

  • 接口:
void start(const QString &program, 
           const QStringList &arguments, 
           QIODevice::OpenMode mode)
  • 示例:
QProcess process;
process.start("C:/Users/Tmp/Test Demo.exe", QStringList());

2.2 配合转义\字符的start接口

  • 接口:
void start(const QString &command, QIODevice::OpenMode mode)
  • 示例:
QProcess process;
process.start("\"C:/Users/Tmp/Test Demo.exe\"");

3. 为什么会这样?

  在问题重现错误例子中使用的start接口为:

void start(const QString &command, QIODevice::OpenMode mode)

  从接口(2.1与2.2)的相似度先提出疑问,为什么一个是program一个是command?

查看了QProcess分析得出program与command的区别是,前者不会对空格进行处理,而后者会把命令字符串以空格进行分割。   

假如command为C:/Users/Tmp/Test Demo.exe,实际上command会被分解为C:/Users/Tmp/TestDemo.exe。这样就会导致C:/Users/Tmp/Test文件找不到的现象。

4. 源码验证疑问

  • QProcess源码先来一波
static QStringList parseCombinedArgString(const QString &program)
{
    QStringList args;
    QString tmp;
    int quoteCount = 0;
    bool inQuote = false;

    // handle quoting. tokens can be surrounded by double quotes
    // "hello world". three consecutive double quotes represent
    // the quote character itself.
    for (int i = 0; i < program.size(); ++i) {
        if (program.at(i) == QLatin1Char('"')) {
            ++quoteCount;
            if (quoteCount == 3) {
                // third consecutive quote
                quoteCount = 0;
                tmp += program.at(i);
            }
            continue;
        }
        if (quoteCount) {
            if (quoteCount == 1)
                inQuote = !inQuote;
            quoteCount = 0;
        }
        if (!inQuote && program.at(i).isSpace()) {
            if (!tmp.isEmpty()) {
                args += tmp;
                tmp.clear();
            }
        } else {
            tmp += program.at(i);
        }
    }
    if (!tmp.isEmpty())
        args += tmp;

    return args;
}

/*!
    \overload

    Starts the command \a command in a new process.
    The OpenMode is set to \a mode.

    \a command is a single string of text containing both the program name
    and its arguments. The arguments are separated by one or more spaces.
    For example:

    \snippet code/src_corelib_io_qprocess.cpp 5

    Arguments containing spaces must be quoted to be correctly supplied to
    the new process. For example:

    \snippet code/src_corelib_io_qprocess.cpp 6

    Literal quotes in the \a command string are represented by triple quotes.
    For example:

    \snippet code/src_corelib_io_qprocess.cpp 7

    After the \a command string has been split and unquoted, this function
    behaves like the overload which takes the arguments as a string list.

    You can disable this overload by defining \c
    QT_NO_PROCESS_COMBINED_ARGUMENT_START when you compile your applications.
    This can be useful if you want to ensure that you are not splitting arguments
    unintentionally, for example. In virtually all cases, using the other overload
    is the preferred method.

    On operating systems where the system API for passing command line
    arguments to a subprocess natively uses a single string (Windows), one can
    conceive command lines which cannot be passed via QProcess's portable
    list-based API. In these rare cases you need to use setProgram() and
    setNativeArguments() instead of this function.

*/
#if !defined(QT_NO_PROCESS_COMBINED_ARGUMENT_START)
void QProcess::start(const QString &command, OpenMode mode)
{
    QStringList args = parseCombinedArgString(command);
    if (args.isEmpty()) {
        Q_D(QProcess);
        d->setErrorAndEmit(QProcess::FailedToStart, tr("No program defined"));
        return;
    }

    const QString prog = args.takeFirst();

    start(prog, args, mode);
}
#endif
  • 从上面源码可以看到start(const QString &command, OpenMode mode)接口内部使用到了parseCombinedArgString接口,而这一接口作用是检查字符串以可空格分解参数。
  • 不想命令行被以空格为分解,则不要使用该接口。

5. 怎么避免混用两个相似的start接口?

  • 在项目(.pro)文件添加以屏蔽start(const QString &command, OpenMode mode)接口的使用。
  • 使用setProgram()setNativeArguments()也能设置命令与参数。
DEFINES += QT_NO_PROCESS_COMBINED_ARGUMENT_START
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-05-28,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Qt君 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 问题重现
  • 2. 解决方案
    • 2.1 使用使用空参数(arguments)的start接口
      • 2.2 配合转义\字符的start接口
      • 3. 为什么会这样?
      • 4. 源码验证疑问
      • 5. 怎么避免混用两个相似的start接口?
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档