QProcess
用于完成启动外部程序,并与之交互通信
一、启动外部程序的两种方式
1)一体式:void QProcess::start(const QString & program,const QStringList &arguments,OpenMode mode = ReadWrite)
外部程序启动后,将随主程序的退出而退出。
2)分离式:void QProcess::startDetached(const QString & program,const QStringList & arguments,const QString&workingDirectory=QString(),qint64 *pid =0)
外部程序启动后,当主程序退出时并不退出,而是继续运行。
二、启动之前需要做的工作:
启动一个外部程序,需要传递外部程序的路径和执行参数,参数用QStringList来带入。
1)设置路径
void QProcess::setProgram(const QString & program)
2)设置参数【可选】
void QProcess::setArguments(const QStringList & arguments)
3)启动
选择启动函数(两种方式)
三、启动状态
外部程序未启动时,其状态是NotRunning;
当启动时,其状态转变为Starting,正在启动,但此时还未调用起来;
启动之后,继续变为Running,同时发射出started()信号,此时,可以对QProcess进行读写操作了;
当退出时,其状态改为NotRunning,并发射出finished()信号。finished()信号会携带退出码和退出状态,可以分别通过exitCode()和exitStatus()来获得。
当发生错误时,QProcess会发出一个error()信号,同样的,也可以通过error()来获得其错误类型,通过state()获得当前程序的状态。
四、QProcess与QIODevice
QProcess继承于QIODevice,因此,我们可以把它当作一个I/O设备进行读写操作。
五、交互
QProcess有两种预定义的输入通道:标准输出stdout与标准错误stderr.
通过setReadChannel可以读取输出的通道。
- 当通道的数据准备就绪时,QProcess会发出readyRead()信号。如果是标准输出,则发出readyReadStandardOutput()信号。
- 如果是标准错误,则发出readyReadStandardError()信号。
常用的读取方式有read(),readAll()或getChar(),也可以通过readAllStandardOutput()和readAllStandardError()读取标准输出和标准错误通道中的数据。
某些程序需要设置环境才能进行特殊的操作。可以通过setEnvironment()来设置环境变量,通过setWorkingDirectory()来设置工作目录,默认的工作路径是当前调用程序的工作路径。
六、同步API
QProcess提供了一系列的函数以提到事件循环来完成同步操作:
1)waitForStarted()//阻塞,直到外部程序启动
2)waitForReadyRead()//阻塞,直到输出通道中的新数据可读
3) waitForBytesWritten()//阻塞,直到输入通道中的数据被写入
4) waitForFinished() //阻塞,直到外部程序结束
** 如果在主线程中调用这些函数,可能会造成当前用户界面不响应。 **
七、QProcess进程类
Qt提供了一个QProcess类用于启动外部程序并与之通信,启动一个新的进程的操作非常简单,只需要将待启动的程序名称和启动参数传递给start()函数即可。
例:
Qobject *parent;
QString program = "tar";
QStringList arguments;
arguments<<"czvf"<<"backup.tar.gz"<<"/home";
QProcess *myProcess= new QProcess(parent);
QProcess->start(program,arguments);
当调用start()函数后,myProcess进程立即进入启动状态,但tar程序尚未被调用,不能读入标准输入输出设备。当进程完成启动后就进入“运行状态”并向外发送出
started()信号,在输入输出方面,QProcess将一个进程看做一个类型的I/O设备,可以像使用QTcpSocket读写流类型的网络连接一样来读写一个进程。
可以通过QIODevice::write()函数向所启动的进程的标准输入写数据,也可以通过QIODeivic::read()、QIODevice::readLine()、QIODevice::getChar()函数从这个进程的标准输出读数据。此外由于QProcess是从QIODevice类继承而来的。
Qt定义了如下的进程错误代码:
错误常量值描述
QProcess::FailedToStart 0 进程启动失败
QProcess::Crashed 1 进程成功后崩溃
QProcess::Timedout 2 最后一次调用waitFor...()函数超时。此时QProcess状态不变,并可以再次调用waitFor...()类型的函数
QProcess::WriteError 3 向进程中写入数据时出错。如进程尚未启动,或者输入通道被关闭时。
QProcee::ReadError 4 从进程中读取数据时出错。如进程尚未启动时
QProcess::UnknownError 5 未知错误。这也是error()函数返回的默认值。
八、进程的标准输出:
-
stdout:通常用于控制台下输出 stderr:通常用于进程打印错误 它们本质上是两个独立的数据流 可以通过调用setReadChanned()函数设置当前的读通道
-
当有可读数据时Qt将发出readyRead()信号 如果是标准输出和标准错误通道中读取数据,还会发出readyReadStandardOutput()信号
-
readAllStandardOutput()函数从标准输出通道中读取数据
-
readAllStandardErrot()函数从标准错误通道中读取数据
-
在进程启动以前以MergedChannels参数调用setReadChannelMode()函数可以把标准输出通道和标准输出错误通道合并。
九
关闭后台进程
//适用于关闭后台进程的方法
QString c = "taskkill /im notepad.exe /f";
int pInt = QProcess::execute(c); //相当于start+waitForFinished。
//关闭后台notepad.exe进程,阻塞式运行,一直占用cpu,成功返回0,失败返回1
qDebug()<<"pInt:"<<pInt;
空格
//1-不带空格。能够启动
process->start("F:/AppInst/115/115com/115com.exe");
//2-带空格,无法启动
process->start("C:/Program Files/HaoZip/HaoZip.exe");
//3-带空格,使用带參模式。能够启动
process->start("C:/Program Files/HaoZip/HaoZip.exe", QStringList("C:/Program Files/HaoZip/HaoZip.exe"));
执行cmd
QProcess p(0);
p.start("cmd", QStringList()<<"/c"<<"ping www.baidu.com");
p.waitForStarted();
p.waitForFinished();
QString strTemp=QString::fromLocal8Bit(p.readAllStandardOutput());
QMessageBox testMassage;
testMassage.setText(strTemp);
testMassage.exec();
QObject *parent;
...
QString program = "./path/to/Qt/examples/widgets/analogclock";
QStringList arguments;
arguments << "-style" << "fusion";
QProcess *myProcess = new QProcess(parent);
myProcess->start(program, arguments);
运行gzip来压缩字符串
QProcess gzip;
gzip.start("gzip", QStringList() << "-c");
if (!gzip.waitForStarted())
return false;
gzip.write("Qt rocks!");
gzip.closeWriteChannel();
if (!gzip.waitForFinished())
return false;
QByteArray result = gzip.readAll();
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
connect(&myProcess, &QProcess::readyRead, this, &MainWindow::showResult);
connect(&myProcess, &QProcess::stateChanged,
this, &MainWindow::showState);
connect(&myProcess, &QProcess::errorOccurred((QProcess::ProcessError),
this, &MainWindow::showError((QProcess::ProcessError));
connect(&myProcess, SIGNAL(finished(int,QProcess::ExitStatus)),
this, SLOT(showFinished(int, QProcess::ExitStatus)));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_clicked()
{
QString program = "cmd.exe";
QStringList arguments;
arguments << "/c dir&pause";
myProcess.start(program, arguments);
}
void MainWindow::showResult()
{
QTextCodec *codec = QTextCodec::codecForLocale();
qDebug() << "showResult: " << endl << codec->toUnicode(myProcess.readAll());
}
void MainWindow::showState(QProcess::ProcessState state)
{
qDebug() << "showState: ";
if (state == QProcess::NotRunning) {
qDebug() << "Not Running";
} else if (state == QProcess::Starting) {
qDebug() << "Starting";
} else {
qDebug() << "Running";
}
}
void MainWindow::showError()
{
qDebug() << "showError: " << endl << myProcess.errorString();
}
void MainWindow::showFinished(int exitCode, QProcess::ExitStatus exitStatus)
{
qDebug() << "showFinished: " << endl << exitCode << exitStatus;
}
环境
QProcess process;
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
env.insert("TMPDIR", "C:\\MyApp\\temp"); // Add an environment variable
process.setProcessEnvironment(env);
process.start("myapp");
Qt只能对QProcess指定的进程读写,不能对其子进程读写。
参考:https://blog.csdn.net/weixin_38893389/article/details/82082912
https://blog.csdn.net/wzj0808/article/details/79367314
https://blog.csdn.net/zww0815/article/details/51275281
【推荐】博客园的心动:当一群程序员决定开源共建一个真诚相亲平台
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】Flutter适配HarmonyOS 5知识地图,实战解析+高频避坑指南
【推荐】凌霞软件回馈社区,携手博客园推出1Panel与Halo联合终身会员
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步