Why QProcess::readAllStandardOutput reads NOT ALL output channel?

Viewed 210

I want to add output from top linux tool to the QTextEdit. Output from top is very large - may be it's reason for why this code:

m_pprocess = new QProcess();
m_pprocess->setCurrentWriteChannel(QProcess::StandardOutput);
m_pprocess->start("top -b -d 5.0");

connect(m_pprocess, &QProcess::readyReadStandardOutput, [this](){

    m_ptexteditProcesses->clear();
    QThread::msleep(1000);
    QByteArray ba = m_pprocess->readAllStandardOutput();
    m_ptexteditProcesses->append(ba);
    qDebug() << ba.size();
    m_ptexteditProcesses->verticalScrollBar()->triggerAction(QScrollBar::SliderToMinimum);
});

behave the next manner:

  1. Despite of update period for the top command 5 seconds, my QTextEdit updates twice with period 1 second and waiting remained 3 - 4 seconds for next top update. Thats why I add QThread::msleep(1000); - just to see this blinking in QTextEdit and recognize thats data writing entirely (if summarize all transaction in 5 second period).

  2. qDebug() show me next picture (1'st number -> [1 sec] -> 2'nd number -> [3 sec] -> 4'th number -> [1 sec] -> ...):

QByteBuffer size

It looks like readAllStandardOutput(); reads not all standard output but 4096 bytes, and only then reads remained bytes (which is about 14000 i.e. there are no some read buffer limit)!

So I can't show entire output of top command in my QTextEdit :) Please help me do this!

UPDATE:

The adding m_pprocess->waitForReadyRead(1); can be little fix like

connect(m_pprocess, &QProcess::readyReadStandardOutput, [this](){

    m_ptexteditProcesses->clear();
    //QThread::msleep(1000);
    QByteArray ba;
    m_pprocess->waitForReadyRead(1);
    ba.append(m_pprocess->readAllStandardOutput());
    m_ptexteditProcesses->append(ba);
    qDebug() << ba.size();
    m_ptexteditProcesses->verticalScrollBar()->triggerAction(QScrollBar::SliderToMinimum);
});

And produce this new one

but is there more elegant solution that allow read standard output in single step?

1 Answers

One possible solution is to make the "top" command run once and when the command is finished reading all the information, and to read it every T seconds then a QTimer can be used:

m_pprocess = new QProcess();
m_pprocess->setCurrentWriteChannel(QProcess::StandardOutput);
m_pprocess->setProgram("top");
m_pprocess->setArguments({"-bn1"});

m_ptimer = new QTimer;
m_ptimer->setSingleShot(true);
m_ptimer->setInterval(5000);
connect(m_ptimer, &QTimer::timeout, m_pprocess, [this]{
    m_pprocess->start();
});

connect(m_pprocess, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), [this](){
    m_ptexteditProcesses->clear();
    QByteArray ba = m_pprocess->readAllStandardOutput();
    m_ptexteditProcesses->append(ba);
    qDebug() << ba.size();
    m_ptexteditProcesses->verticalScrollBar()->triggerAction(QScrollBar::SliderToMinimum);
    m_ptimer->start();
});

m_pprocess->start();
Related