QProcess проблемы, вывод процесса - PullRequest
4 голосов
/ 05 мая 2011

Я пытаюсь выяснить использование QProcess. Я посмотрел на Qt doc без удачи.
http://doc.qt.io/qt-4.8/qprocess.html

ПРИМЕРЫ ПРОБЛЕМЫ.

Пример 1: Код ниже работает.

    #include <QtCore/QCoreApplication>
#include <QTextStream>
#include <QByteArray>
#include <QProcess>    

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    QTextStream qout(stdout);    

    QProcess cmd;

    cmd.start("cmd");
    if (!cmd.waitForStarted())  {
        return false;
    }

    cmd.waitForReadyRead();
    QByteArray result = cmd.readAll();
    //qout << result.data() << endl;   //console junk captured, don't show. 

    //My test command
    cmd.write("echo hello");
    cmd.write("\n");

    //Capture my result
    cmd.waitForReadyRead();
    //This is my command shown by cmd, I don't show it, capture & discard it.
    result = cmd.readLine();
    //Read result of my command ("hello") and the rest of output like cur dir.   
    result = cmd.readAll();    
    qout << result.data();

    qout << "\n\n---End, bye----" << endl;
    return a.exec();
}

Выход приведенного выше кода

привет

F:\Dev_Qt\expControllingExtConsoleApps-build-desktop>

---End, bye----

Проблема в том, что если я попытаюсь использовать ipconfig или 7zip таким способом через Qprocess и консоль cmd, я не смогу увидеть какие-либо выходные данные из ipconfig или 7zip. Я не знаю, если что-то даже сделано, если что-то сделано, то почему я не вижу результат? Код ниже иллюстрирует.

Пример 2: Не работает. Не могу использовать ipconfig.

#include <QtCore/QCoreApplication>
#include <QTextStream>
#include <QByteArray>
#include <QString>
#include <QProcess>    

int main(int argc, char *argv[])
{
   QCoreApplication a(argc, argv);
   QTextStream qout(stdout);

   QProcess cmd2;
    cmd2.setWorkingDirectory("C:/Program Files/7-Zip");   //not needed in this example.
    cmd2.setReadChannel(QProcess::StandardOutput);
    cmd2.setProcessChannelMode(QProcess::MergedChannels);

    cmd2.start("cmd");
    if (!cmd2.waitForStarted())
    {
        qout << "Error: Could not start!" << endl;
        return false;
    }

    cmd2.waitForReadyRead();
    QByteArray result = cmd2.readAll();
    qout << result.data() << endl;      //Console version info, etc.

    //My command
    cmd2.write("ipconfig");
    cmd2.write("\n");

    //Capture output of ipconfig command
    //DOES NOT WORK!!
    cmd2.waitForReadyRead();
    while (! cmd2.atEnd())
    {
        result = cmd2.readLine();
        qout << result;
        result.clear();
    }
    qout << endl;

    qout << "\n\n---end----" << endl;
    return a.exec();

}

Вывод ниже, отсутствует информация о соединении ipconfig. Выходные данные ipconfig не регистрируются вообще.

Microsoft Windows XP [Версия 5.1.2600] (C) Copyright 1985-2001 Microsoft Corp.

C: \ Program Files \ 7-Zip> ipconfig

--- конец ----

Должно быть так (с результатом ipconfig).

Microsoft Windows XP [Версия 5.1.2600] (C) Copyright 1985-2001 Microsoft Corp.

C: \ Документы и Настройки \ Noname> IPCONFIG

Конфигурация Windows IP

Ethernet-адаптер Local Area Подключение:

    Connection-specific DNS Suffix  . :
    IP Address. . . . . . . . . . . . : 192.172.148.135
    Subnet Mask . . . . . . . . . . . : 255.255.255.0
    Default Gateway . . . . . . . . . : 192.172.148.177

C: \ Documents and Settings \ noname>

Очевидно, что выходные данные должны были немного отличаться от указанных выше, но информация о соединении, которая является выводом "ipconfig", должна быть получена. Таким же образом, если я пытаюсь использовать 7zip через консоль cmd ... Я не могу увидеть / захватить любой вывод 7zip. Итак, мой вопрос: как я могу использовать приложения командной строки, такие как ipconfig и 7zip, через QProcess и консоль cmd и видеть результат вывода этих приложений?

Пример 3: 7zip не работает

#include <QtCore/QCoreApplication>
#include <QTextStream>
#include <QByteArray>
#include <QProcess>    

int main(int argc, char *argv[])
{
   QCoreApplication a(argc, argv);
   QTextStream qout(stdout);

    QProcess cmd2;
    cmd2.setWorkingDirectory("C:/Program Files/7-Zip");
    cmd2.setReadChannel(QProcess::StandardOutput);
    cmd2.setProcessChannelMode(QProcess::MergedChannels);

    cmd2.start("cmd");
    if (!cmd2.waitForStarted()) {
        return false;
    }

    //My Command
    cmd2.write("7z.exe");
    cmd2.write("\n");

    //Capture output of ipconfig command
    cmd2.waitForReadyRead();
    QByteArray result;

    while (! cmd2.atEnd()) {
        result = cmd2.readLine();
        qout << result;
        result.clear();
    }
    qout << endl;

    qout << "\n\n---end----" << endl;
    return a.exec();
}

Выход ниже. Не показывает ничего из 7zip.

Microsoft Windows XP [Версия 5.1.2600] (C) Copyright 1985-2001 Microsoft Corp.

C: \ Program Files \ 7-Zip> 7z.exe

--- конец ----

Ожидается, что объем производства будет соответствовать ...

Microsoft Windows XP [Версия 5.1.2600] (C) Copyright 1985-2001 Microsoft Corp.

C: \ Documents and Settings \ noname> cd C: \ Program Files \ 7-Zip

C: \ Program Files \ 7-Zip> 7z.exe

7-Zip 9.15 beta Авторские права (c) 1999-2010 Игорь Павлов 2010-06-20

Использование: 7z [...] [...] [<@Listfiles ...>]

a: Добавить файлы в архив
b: контрольный показатель d: удалить файлы из Архив e: Извлечение файлов из архив (без использования каталога имена) l: список содержимого архива
t: проверить целостность архива u: Обновить файлы в архиве x: eXtract файлы с полными путями
-ai [r [- | 0]] {@ listfile |! wildcard}: Включить архивы
-ax [r [- | 0]] {@ listfile |! wildcard}: eXclude архивы -bd: отключить процентный показатель
-i [r [- | 0]] {@ listfile |! wildcard}: Включить имена файлов -m {Параметры}: установить метод сжатия
-o {Каталог}: установить выходной каталог -p {Пароль}: установить пароль -r [- | 0]: подкаталоги рекурсоров -scs {UTF-8 | WIN | DOS}: установить кодировку для файлов списка -sfx [{имя}]: создать архив SFX -si [{имя}]: прочитать данные из stdin -slt: показать техническую информацию для команды l (список) -so: записать данные в stdout -ssc [-]: установить чувствительный регистр режим -ssw: сжатие общих файлов
-t {Тип}: установить тип архива -u [-] [p #] [q #] [r #] [x #] [y #] [z #] [! newArchiveName]: Обновить параметры -v {Размер} [b | k | m | g]: Создать тома -w [{путь}]: назначить Рабочий каталог. Пустой путь означает временный каталог
-x [r [- | 0]]] {@ listfile |! wildcard}: исключить имена файлов -y: предположить, что да включен все запросы

C: \ Program Files \ 7-Zip>

Ответы [ 2 ]

4 голосов
/ 07 июля 2013

Несмотря на то, что Дариуш Шарсиг уже предоставил решение проблемы, я хотел бы указать на то, что, по моему мнению, является актуальной проблемой (ями), которая может быть решена с использованием механизма сигнальных щелей.

Проблема 1. Условие в вашем цикле while основано на bool QProcess::atEnd () const, что соответствует Документации QProcess Состояния:

Повторно реализовано из QIODevice :: atEnd (),

Возвращает true, если процесс не запущен, и больше нет данных для чтения;в противном случае возвращает false.

Но если вы ищете документацию для QIODevice :: atEnd () , в нем говорится:

Возвращает true, если текущийпозиция чтения и записи находится в конце устройства (т.е. на устройстве больше нет данных для чтения);в противном случае возвращает false.

Для некоторых устройств atEnd () может возвращать true, даже если есть больше данных для чтения. Этот особый случай применяется только к устройствам, которые генерируют данные в прямом ответе на вызов read ()(например, файлы / dev или / proc в Unix и Mac OS X или консольный ввод / stdin на всех платформах ).

Решение 1. Измените условие цикла while, чтобы проверить состояние вашего процесса: while(cmd2.state()!=QProcess::NotRunning){.

Задача 2. Вы используете cmd2.waitForReadyRead(); вне цикла.Возможно, некоторые данные уже готовы для чтения, а когда вы закончите чтение, появятся другие:

  • вы читаете только что написанные команды: ipconfig\n
  • ipconfig занимает некоторое времязапустить и отправить текст на консоль.Но к тому времени вы уже вышли из цикла, потому что atEnd() дал значение true, даже если ваш процесс все еще работает.

Решение 2. поместите waitForReadyRead() внутри цикла.

Следствие 2. waitForReadyRead() сообщит вам, когда будут доступны данные, которые могут содержать более одной строки, поэтому вам также следует изменить cmd2.ReadLine() на cmd2.ReadAll().

Проблема 3. Как описано в QProcess :: closeWriteChannel ()

Закрытие канала записи необходимо для программ, которые читают вводданные до тех пор, пока канал не будет закрыт.

Решение 3. Одна из следующих опций должна работать после завершения записи ваших входных данных

  • Завершить процесс: cmd2.write("exit\n");
  • закрыть канал записи: cmd2.closeWriteChannel();

Рабочий код:

#include <QtCore/QCoreApplication>
#include <QTextStream>
#include <QByteArray>
#include <QString>
#include <QProcess>    

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    QTextStream qout(stdout);
    QByteArray result;
    QProcess cmd2;

    cmd2.setReadChannel(QProcess::StandardOutput);
    cmd2.setProcessChannelMode(QProcess::MergedChannels);
    cmd2.start("cmd");
    if (!cmd2.waitForStarted()){
        qout << "Error: Could not start!" << endl;
        return 0;
    }
    cmd2.write("ipconfig\n");
    cmd2.closeWriteChannel();   //done Writing

    while(cmd2.state()!=QProcess::NotRunning){
        cmd2.waitForReadyRead();
        result = cmd2.readAll();
        qout << result;
    }
    qout << endl << "---end----" << endl;
    return a.exec();
}

Я написал этот ответ, чтобы объяснить, как я понимаю вашепроблема и нашел решение, но хотел бы подчеркнуть, что Предпочтительное решение заключается в использовании Механизм сигналов / слотов, представленный Dariusz .

4 голосов
/ 05 мая 2011

я вижу одну большую проблему.Под окнами вы вводите комментарий, нажимая клавишу Enter.Написание

cmd.write("command");
cmd.write("\n");


просто недостаточно, вы должны написать

cmd.write("command");
cmd.write("\n\r");

Обратите внимание на трейлинг \ r.Попробуйте это, это должно работать лучше, и лучше я имею в виду 7zip.Я не знаю, получите ли вы ipconfig для правильной работы.

Удачи и наилучших пожеланий
D

РЕДАКТИРОВАТЬ Вот рабочее решение:


#include <QtCore/QCoreApplication>
#include <QtCore/QProcess>
#include <QtCore/QString>
#include <QtCore/QTextStream>

// Not clean, but fast
QProcess *g_process = NULL;

// Needed as a signal catcher
class ProcOut : public QObject
{
  Q_OBJECT
public:
  ProcOut (QObject *parent = NULL);
  virtual ~ProcOut() {};

public slots:
  void readyRead();
  void finished();
};

ProcOut::ProcOut (QObject *parent /* = NULL */):
QObject(parent)
{}

void
ProcOut::readyRead()
{
  if (!g_process)
    return;

  QTextStream out(stdout);
  out << g_process->readAllStandardOutput() << endl;
}

void
ProcOut::finished()
{
  QCoreApplication::exit (0);
}

int main (int argc, char **argv)
{
  QCoreApplication *app = new QCoreApplication (argc, argv);

  ProcOut *procOut = new ProcOut();
  g_process        = new QProcess();

  QObject::connect (g_process, SIGNAL(readyReadStandardOutput()),
    procOut, SLOT(readyRead()));
  QObject::connect (g_process, SIGNAL(finished (int, QProcess::ExitStatus)),
    procOut, SLOT(finished()));

  g_process->start (QLatin1String ("cmd"));
  g_process->waitForStarted();

  g_process->write ("ipconfig\n\r");

  // Or cmd won't quit
  g_process->write ("exit\n\r");

  int result = app->exec();

  // Allright, process finished.
  delete procOut;
  procOut = NULL;

  delete g_process;
  g_process = NULL;

  delete app;
  app = NULL;

  // Lets us see the results
  system ("pause");

  return result;
}

#include "main.moc"

Надеюсь, это поможет.Он работал каждый раз на моей машине.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...