这个问题困扰着我,因为它应该工作,但遗憾的是它没有工作。我试图实现的是读取某个流程的标准输出,并让另一个流程处理它,即打印出来。
产生输出的过程如下所示:
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
int main() {
for (int i = 0; i < 100; i++) {
printf("yes %dn",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时,我得到了所有的输出,但不是通过信号/插槽,而是直接在控制台中。
我不明白,因为它在另一个使用Qt4.8的应用程序中工作。
我的问题是,有人遇到过同样的问题吗?或者有人知道我如何才能得到预期的行为吗?
您提供的答案中的问题在于误解了阅读的工作原理。它只是返回您在那里得到的任何数据,无论是否有行结尾。通过生成线程并在行之间休眠,您可以有效地以行大小的块发送进程间数据,因为当您等待足够长的时间时,管道会被刷新。
所以,在工作时,你的答案并不是应该怎么做。你需要使用readLine()
将传入的数据切成行。以下是具有以下特性的示例:
- 只有一个可执行文件:)
- 只使用Qt api。这减少了运行时内存消耗
- 两个进程都干净地终止
- 代码的数量是尽可能少的
// 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"
根据您发布的代码,您将使用以下代码连接到类插槽:-
connect(process,SIGNAL(readyRead()),someClass,SLOT(onReadyReadStdOutput()));
但是类中的函数是这样声明的:-
void SomeClass::onReadyRead();
如果您希望调用onReadyRead,那么您应该在SLOT中调用它,而不是onReadyReadStdOutput。因此,请将您的连接更改为:-
connect(process,SIGNAL(readyRead()),someClass,SLOT(onReadyRead()));
我解决了我的问题。
如果进程是用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();
}
TestP main.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();
}