4

这个问题困扰着我,因为它应该可以工作,但遗憾的是它没有。我试图实现的是读取某个进程的标准输出并让另一个进程处理它,即打印出来。

产生输出的过程如下所示:

#include <stdio.h>
#include <stdlib.h>
#include <iostream>

int main() {
    for (int i = 0; i < 100; i++) {
        printf("yes %d\n",i);
        fflush(stdout);
        sleep(1);
    }
    return 0;
}

该过程在另一个应用程序中启动,如下所示:

#include <QProcess>
...
QProcess * process = new QProcess;
SomeClass * someClass = new SomeClass(process);
connect(process,SIGNAL(readyRead()),someClass,SLOT(onReadyRead()));

process->start("../Test/Test",QStringList());
if (!process->waitForStarted(4000)) {
    qDebug() << "Process did not start.";
}
...
void SomeClass::onReadyRead() {
    qDebug() << "Reading:" << process->readAllStdOutput();
}

我的预期输出是:

Reading: yes 0
Reading: yes 1
...
Reading: yes 99

但是我根本没有输出。当我使用 QCoreApplication 时,我得到所有输出,但不是通过信号/插槽,而是直接在控制台中。

我不明白,因为它适用于另一个使用 Qt 4.8 的应用程序。

我的问题是,是否有人遇到同样的问题,或者有人知道我如何获得预期的行为?

4

3 回答 3

4

您提供的答案中的问题在于误解了阅读的方式。它只是返回您在那里获得的任何数据,无论是否有行尾。通过产生一个线程并在行之间休眠,您可以有效地以行大小的块发送进程间数据,因为当您等待足够长的时间时管道会被刷新。

因此,您在工作时的回答并不是真正应该如何去做。您需要使用readLine()将传入的数据切成几行。以下是具有以下品质的示例:

  1. 只有一个可执行文件:)
  2. 仅使用 Qt api。这减少了运行时内存消耗。
  3. 两个进程都干净地终止。
  4. 代码量尽可能少。

// https://github.com/KubaO/stackoverflown/tree/master/questions/process-17856897
#include <QtCore>

QTextStream out{stdout};

class Slave : public QObject {
    QBasicTimer m_timer;
    int m_iter = 0;
    void timerEvent(QTimerEvent * ev) override {
        if (ev->timerId() == m_timer.timerId()) {
            out << "iteration " << m_iter++ << endl;
            if (m_iter > 35) qApp->quit();
        }
    }
public:
    Slave(QObject *parent = nullptr) : QObject(parent) {
        m_timer.start(100, this);
    }
};

class Master : public QObject {
    Q_OBJECT
    QProcess m_proc{this};
    Q_SLOT void read() {
        while (m_proc.canReadLine()) {
            out << "read: " << m_proc.readLine();
            out.flush(); // endl implicitly flushes, so we must do the same
        }
    }
    Q_SLOT void started() {
        out << "started" << endl;
    }
    Q_SLOT void finished() {
        out << "finished" << endl;
        qApp->quit();
    }
public:
    Master(QObject *parent = nullptr) : QObject(parent) {
        connect(&m_proc, SIGNAL(readyRead()), SLOT(read()));
        connect(&m_proc, SIGNAL(started()), SLOT(started()));
        connect(&m_proc, SIGNAL(finished(int)), SLOT(finished()));
        m_proc.start(qApp->applicationFilePath(), {"dummy"});
    }
};

int main(int argc, char *argv[])
{
    QCoreApplication app{argc, argv};
    if (app.arguments().length() > 1)
        new Slave{&app}; // called with an argument, this is the slave process
    else
        new Master{&app}; // no arguments, this is the master
    return app.exec();
}

#include "main.moc"
于 2013-09-03T22:33:14.713 回答
0

根据您发布的代码,您将通过以下方式连接到类插槽:-

connect(process,SIGNAL(readyRead()),someClass,SLOT(onReadyReadStdOutput()));

但是类中的函数是这样声明的:-

void SomeClass::onReadyRead();

如果您希望调用 onReadyRead,那么您应该在 SLOT 中调用它,而不是 onReadyReadStdOutput。因此,将您的连接更改为: -

 connect(process,SIGNAL(readyRead()),someClass,SLOT(onReadyRead()));
于 2013-07-25T12:13:51.650 回答
-1

好吧,我解决了我的问题。

如果进程以 startDetached() 启动,它将不会收到来自readyRead()readyReadStandardOutput()readyReadStandardError()的信号。

因此,只需使用 start() 启动它就可以解决问题。

但是我注意到,如果我开始并执行 while 循环并在main()中打印,即使它以 \n 结尾,它也会立即读取所有内容。所以我在一个线程中启动了while循环,这个问题也得到了解决。一切都按预期打印。

#include <QThread>

class Thread : public QThread 
{
    Q_OBJECT

public:
    explicit Thread(QObject *parent = 0) : QThread(parent) {}

protected:
    void run() {
        for (int i = 0; i < 100; i++) {
            std::cout << "yes" << i << std::endl;
            msleep(200);
        }
        exit(0);
    }
};

int main(int argc, char ** argv) {
    QCoreApplication app(argc,argv);
    Thread * t = new Thread();
    t->start();
    return app.exec();
}

测试主程序.cpp

#include <QProcess>
#include <iostream>

class Controller : public QObject 
{
    Q_OBJECT
private:
    QProcess * process;

public:
    Controller(QObject *parent = 0) : 
        QObject(parent), process(new QProcess) {}

    void init(const QString &program) {
        connect(process,SIGNAL(readyRead()),this,SLOT(readStdOut()));
        connect(process,SIGNAL(started()),this,SLOT(onStarted()));
        connect(process,SIGNAL(finished(int)),this,SLOT(onFinished(int)));
        process->start(program);
    }

private slots:
    void readStdOut() {
        std::cout << "YES " << QString(process->readAllStandardOutput()).toUtf8().constData() << std::endl;
    }
    void onStarted(){
        std::cout << "Process started" << std::endl;
    }
    void onFinished(int) {
        std::cout << "Process finished: " << signal << std::endl;
    }
};

int main(int argc, char *argv[]) {
    QCoreApplication a(argc, argv);
    Controller c;
    c.init("../Test/Test");
    return a.exec();
}
于 2013-07-25T19:41:58.643 回答