在 Qt 中获取输出:'QProcess::start()' 和 'QProcess:readAllStandardOutPut()'

Posted

技术标签:

【中文标题】在 Qt 中获取输出:\'QProcess::start()\' 和 \'QProcess:readAllStandardOutPut()\'【英文标题】:Get Output in Qt: 'QProcess::start()' and 'QProcess:readAllStandardOutPut()'在 Qt 中获取输出:'QProcess::start()' 和 'QProcess:readAllStandardOutPut()' 【发布时间】:2018-04-23 08:40:25 【问题描述】:

平台:Windows10 我使用QProcess::start 执行Python文件(在同一个目录中),但我 无法从 readAllStandardOutput 函数获取结果。

Python文件代码:

test.py

print “hello,world”

Qt:

#include <QProcess>
#include <QStringList>
#include <QByteArray>
#include <QDebug>

void fun1()
    QProcess process;
    process.start("python test.py");
    process.waitForFinished();
    QByteArray a = process.readAllStandardOutput();


    qDebug()<<a;


int main()
    fun1();

我执行test.py时可以得到输出,但是当我使用readAllStandardOutput时我无法得到它。它只是打印没有数据的“”。

#include <QProcess>
#include <QStringList>
#include <QByteArray>
#include <iostream>
#include <QDebug>

void fun2()
    QStringList args("F:/test.py");
    QProcess process;
    process.execute(QString("Python.exe"), args);
    QByteArray a = process.readAllStandardOutput();
    process.waitForFinished();
    qDebug()<<a;



int main()
    fun1();
    qDebug<<"--------";
    fun2();

fun2函数中,函数execute()可以在Qt终端print "hello,world",但是我不能用readAllStandardOutput函数得到标准输出。不知道为什么还打印“”没有数据?

因为我想使用python模块“请求”直接访问一个url,所以我希望我的C++代码可以执行这个python文件。所以,如果你有更好的方法,请告诉我。

【问题讨论】:

【参考方案1】:

当使用QProcess::start() 时,进程在另一个线程中启动并异步执行,以避免阻塞应用程序的GUI 线程(如果您有GUI)。使用waitForReadyRead() 也会阻止您的应用程序的执行,直到进程结束。

您可以考虑使用 Qt 的信号/槽系统在可用时捕获进程的输出,而不会阻塞主线程。

此版本的 fun1() 需要 C++11:

void fun1()
    // instantiate dynamically to avoid stack unwinding before the process terminates
    QProcess* process = new QProcess(); 

    // catch data output
    QObject::connect(process, &QProcess::readyRead, [process] () 
        QByteArray a = process->readAll();
        qDebug() <<  a;
    );

    // delete process instance when done, and get the exit status to handle errors.
    QObject::connect(process, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
                     [=](int exitCode, QProcess::ExitStatus /*exitStatus*/)
        qDebug()<< "process exited with code " << exitCode;
        process->deleteLater();
    );

    // start the process after making signal/slots connections 
    process->start("python test.py");

通过这种方式,您还可以管理执行错误,或者至少让用户意识到这一点。

【讨论】:

非常感谢,你的回答很详细,我找到了一个很好的解决方案来完成我的工作。 @Gabriella Giordano ,我认为QObject::connect 应该放在process-&gt;start() 之前 @MohammadKanan 是的,你是对的。刚刚编辑。谢谢:)【参考方案2】:

不幸的是,在 Qt 中获取进程输出有点麻烦。

这是我在一个项目中的做法:

QProcess process;
process.setProcessChannelMode(QProcess::MergedChannels);
process.start(processToStart, arguments)

// Get the output
QString output;
if (process.waitForStarted(-1)) 
    while(process.waitForReadyRead(-1)) 
        output += process.readAll();
    

process.waitForFinished();

这可能会引发几个问题:

setProcessChannelMode(QProcess::MergedChannels) 将合并输出通道。各种程序写入不同的输出。有些使用错误输出进行正常日志记录,有些使用“标准”输出,有些则两者兼而有之。最好合并它们。

readAll() 读取目前可用的所有内容。

它被放入一个带有 waitForReadyRead(-1) 的循环中(-1 表示没有超时),这将阻塞直到有内容可供读取。这是为了确保所有内容都被实际读取。 在进程完成后简单地调用 readAll() 被证明是非常不可靠的(缓冲区可能已经是空的)。

【讨论】:

谢谢,我知道为什么我不能得到应该使用 waitForReadyRead() 函数的结果。【参考方案3】:

使用 waitForReadyRead() Process API 读取数据。 waitForReadyRead() 阻塞,直到当前读取通道上有新数据可供读取。

void fun1()
    QProcess process;
    process.start("python test.py");
    process.waitForReadyRead();
    QByteArray a = process.readAllStandardOutput();


    qDebug()<<a;

【讨论】:

以上是关于在 Qt 中获取输出:'QProcess::start()' 和 'QProcess:readAllStandardOutPut()'的主要内容,如果未能解决你的问题,请参考以下文章

在Qt中实时获取cmd命令的输出

在qt c++中获取Json数组中Qstring的输出

如何从 Qt 5.12 中的 QJSEngine 获取标准输出?

Qt QProcess

QT软件开发: QProcess启动进程完成交互并获取输出

项目实战:Qt终端命令模拟工具 v1.0.0(实时获取命令行输出,执行指令,模拟ctrl+c中止操作)