在Qt中使用QProcess调用外部可执行文件(.exe文件)

最近实现了把Python文件打包成exe可执行文件,所以就想试一下看看能不能在Qt中使用类来调用这个exe可执行文件,并且完成数据的传递。

1.使用start()函数启动程序

1.1认识函数的参数

QProcess是Qt中一个专门调用外部可执行程序的类,其中start函数是QProcess对象对象启动外部程序的默认方法,我们可以使用这个对象来获取程序的输出数据和错误信息。默认情况下start函数不会阻塞当前线程,只是启动一个新的子进程来执行另一个程序,并立即返回。start函数的原型是:
void start(const QString &program, const QStringList &arguments, OpenMode mode = ReadWrite)

  • 第一个参数是一个字符串类型的数据,是可执行程序的路径
  • 第二个参数是一个字符串列表类型的数据,存放的是你想要传入给可执行程序的参数,当然,没有参数的话可以忽略,不用关注第二个参数。
  • 下面是一个例子:
//创建调用可执行程序的类
QProcess * process = new QProcess(this);
//启动程序,并输入参数
process->start("ali", QStringList() << "qt究竟厉害在什么地方?");

其中,"ali"占据路径的位置,后面的QStringList() << "qt究竟厉害在什么地方?"占据传入参数的位置。

1.2可执行程序的绝对路径、相对路径

接上面的名为"ali"的可执行程序,这个程序与qt的可执行文件(该项目中生成的是"AiChat.exe")处在同一个目录下(如下图1.1)

图1.1:

python 调用exe传参 并获取返回值_可执行程序

当然也可以使用绝对路径:

//测试使用的绝对路径
//QString path = "C:/Users/weiru/Desktop/Qt5ProjectDocument/Qt5ProjectDocument/build-AiChat-Desktop_Qt_5_14_2_MinGW_64_bit-Debug/debug/ali";

1.3启动 和 结束的状态判断

调用start函数之后我们可以监控程序的运行状态,一个是是否启动成功,一个是程序是否正常结束

//waitForStarted()函数与waitForFinished()函数都会使得当前线程处于阻塞状态

//检测程序是否正常启动
if (!process->waitForStarted()) {
	qCritical() << "无法启动程序";
}

//检测程序是否正常结束
if (!process->waitForFinished()) {
	qCritical() << "程序未正常结束";
}

1.4外部可执行程序异常的情况

  • 如果外部可执行程序成功启动了,但是在运行过程中出现错误了我们又该如何处理哪?
  • 如果调用的可执行程序成功结束了,并且带有返回的数据,我们又该如何处理哪?
    答:使用信号和槽的机制处理异常结束信号和终止信号。如:
//链接信号到槽函数,处理错误
connect(process, SIGNAL(readyReadStandardError()), this, SLOT(readStandardError()));

其中,readStandardError()函数是我们自己定义的槽函数,其实现如下:

/***
 * 函数功能:槽函数,处理调用的exe程序发生意外的情况
***/
void AiModels::readStandardError()
{
	//获取错误信息
    QByteArray error = process->readAllStandardError();

	//输出错误信息
    qDebug() << error;
}

1.5QProcess类中其他的调用exe可执行文件的函数

  • QProcess::startDetached()函数,类似于start(),但不会阻塞当前线程,而是让子进程独立运行。返回值为false表示无法启动。
  • QProcess::execute()函数,同样用于启动新的子进程,但会阻塞直到子进程完成。

2.接收exe可执行程序返回的字符串

我们已经在使用start函数的过程中实现了往外部可执行程序中传递数据,现在我们尝试一下接收来自外部可执行程序的输出。但是当我看到打印出来的数据时,发现全是乱码,这肯定是不同编码的锅了。

2.1使用信号和槽函数机制接收返回数据

在槽函数调用接口,获取exe程序在控制台的输出,使用的函数是
QByteArray readAllStandardOutput()这个函数返回一个字节列表类型的数据。
示例:

//连接输出信号和槽,
connect(process, SIGNAL(readyReadStandardOutput()), this, SLOT(readStandardOutput()));

//自定义的槽函数readStandardOutput()实现
void AiModels::readStandardOutput()
{
	//获取返回的数据
    QByteArray output = process->readAllStandardOutput();

    //输出结果
    qDebug() << unicodeStr;
}

2.2字符乱码问题

首先,我调用exe程序是用python写的,输出的数据直接是print打印在控制台的,这个输出的数据编码在windows控制台上默认的是GBK编码,所以我们的任务就是将GBK编码的数据转换成Unicode(qt中默认的Unicode字符集是UTF-8编码)字符集即可。qt中的处理文本编码转换类是QTextCodec,我们就使用这个类试一下吧。下面是代码:

//获取输出的数据,是一个字节数组
QByteArray output = process->readAllStandardOutput();

//创建对象,并设置接收数据的编码方式
QTextCodec *codec = QTextCodec::codecForName("GBK");
//转换成Unicode编码
QString unicodeStr = codec->toUnicode(output);

//输出结果
qDebug() << unicodeStr;

经验证,数据可以正常输出了!!!

3.以下是该博客使用的全部.cpp代码了,类的声明(.h文件)除外,注释部分略有不同,请忽略,以上面的为准。

/***
 * 函数功能:此函数仅供测试一些想法时使用
***/
void AiModels::test2()
{
    //链接信号到槽函数,处理输出和错误
    connect(process, SIGNAL(readyReadStandardOutput()), this, SLOT(readStandardOutput()));
    connect(process, SIGNAL(readyReadStandardError()), this, SLOT(readStandardError()));


    qDebug() << "开始进入测试";
    //测试使用的绝对路径
    //QString path = "C:/Users/weiru/Desktop/Qt5ProjectDocument/Qt5ProjectDocument/build-AiChat-Desktop_Qt_5_14_2_MinGW_64_bit-Debug/debug/ali";
    //process->start(path, QStringList() << "qt中的QProcess中的start函数如何设置相对路径");

    process->start("ali", QStringList() << "qt究竟厉害在什么地方?");

    // 等待程序执行完成
    if (!process->waitForStarted()) {
        // 处理启动失败
        qCritical() << "无法启动程序";
     }

     if (!process->waitForFinished()) {
        // 处理未正常结束的情况
        qCritical() << "程序未正常结束";
      }

    qDebug() << "测试程序执行结束";
}


/***
 * 函数功能:槽函数,处理exe可执行程序的返回值
***/
void AiModels::readStandardOutput()
{
    QByteArray output = process->readAllStandardOutput();

    //GBK编码转换成字符
    QTextCodec *codec = QTextCodec::codecForName("GBK");
    QString unicodeStr = codec->toUnicode(output);

    //输出结果
    qDebug() << unicodeStr;
}



/***
 * 函数功能:槽函数,处理调用的exe程序发生意外的情况
***/
void AiModels::readStandardError()
{
    QByteArray error = process->readAllStandardError();
    qDebug() << error;
}