QProcess — одновременно мощный и удобный модуль библиотеки Qt для запуска и управления процессами. Нельзя забывать, что он еще и весьма опасен. Однако здесь мы не будем затрагивать вопросы информационной безопасности, а лишь ограничимся базовыми приемами использования QProcess.
РЕКОМЕНДУЕМ: Способы повышения продуктивности для программиста
Запуск другого приложения
Допустим, вы хотите, чтобы ваше приложение могло вызывать другую программу в виде независимого процесса. Сделать это очень легко:
1 2 3 4 |
void runTest() { static const QString PROGRAM_NAME = "notepad"; // Для примера - Блокнот QProcess::startDetached( PROGRAM_NAME ); } |
В приведенном примере осуществляется запуск приложения PROGRAM_NAME, которое начнет существовать само по себе. Даже после завершения вашей программы с этим кодом процесс продолжит свою работу совершенно независимо.
Обратите внимание, что startDetached() — статическая функция-член класса QProcess. При этом она может принимать еще несколько параметров: список аргументов в виде QStringList; рабочую директорию; и указатель на int, в котором возвращает идентификатор нового процесса.
Графический интерфейс для консольного приложения
Это решение является довольно распространенным в мире Linux, где большинство утилит изначально выходят в форме консольных приложений. Однако не всем пользователям это нравится. По этой причине и появляются надстройки с графическим интерфейсом, которые являются посредниками между пользователями и исходной консольной утилитой. Например, QtCreator и многие другие IDE для интеграции компиляторов и систем контроля версий используют именно этот прием.
Получение информации от другого приложения через стандартный поток вывода
В большинстве случаев вам достаточно передать нужные аргументы на вход приложению и дождаться от него ответа:
1 2 3 4 5 6 7 8 9 10 |
void readTest() { QProcess process; process.start( "lsusb", QStringList() << "-t" ); if( !process.waitForStarted() || !process.waitForFinished() ) { return; } qDebug() << process.readAllStandardError(); qDebug() << process.readAllStandardOutput(); } |
В приведенном примере мы запускаем lsusb -t (утилита для Linux). Поскольку результат выводится мгновенно, мы ждем завершения процесса с помощью waitForFinished() и выводим то, что приложение отправило в стандартные потоки вывода stderr и stdout. Если же приложение выводит результаты не сразу, а постепенно в течение нескольких секунд или минут, то лучше воспользоваться сигналами readyReadStandardError() и readyReadStandardOutput(), организовав работу в асинхронном режиме.
Основным преимуществом этого кода является то, что вы можете не иметь библиотек и исходных кодов, которые обеспечивают соответствующий функционал. Однако производительность снижается, поэтому если скорость работы критична, то придется искать альтернативные варианты решения.
Обмен сообщениями с процессом
Вы можете не только читать то, что приложение пишет в стандартные потоки вывода, но и сами писать в поток ввода процесса:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
void writeReadTest() { QProcess process; process.start( "cat" ); if( !process.waitForStarted() ) { return; } process.write( "Hello, world!" ); process.closeWriteChannel(); if( !process.waitForFinished() ) { return; } qDebug() << process.readAllStandardError(); qDebug() << process.readAllStandardOutput(); } |
Принцип работы этого примера очень похож на то, что мы видели раньше. Однако теперь внешнее приложение реагирует на то, что мы подаем ему в поток ввода stdin. Все, что мы отправляем в cat, вернется нам обратно в результате вызова readAllStandardOutput(). Обратите внимание, что завершение процесса происходит после вызова closeWriteChannel() (равносильно нажатию Ctrl+D).
Заключение
Мы рассмотрели два базовых способа использования QProcess. Возможно, в вашей работе они никогда и не понадобятся, но знать о них не будет лишним.
РЕКОМЕНДУЕМ: Десять советов по созданию гибкого программного кода