前言   在Qt程序开发过程中,往往我们会调用一些外部的程序,实现特定的功能,并减少开发工作量。例如有一个项目需要使用Https接口下载一些文件和上传下载一些数据,Qt本身虽然封装了OpenSSL的接口,但是安装包中SDK并不带编译完成的OpenSSL的库文件,需要用户自己手动编译对应版本的OpenSSL(Qt对应的OpenSSL版本号可以调用QSslSocket::sslLibraryBuildVersionString()查看),msvc版本相对比较好编译,但是mingw版本就很费事。关于mingw编译三方库可以参考我的另外一篇。所以最后项目采用wget for windows,利用wget的功能去实现我们想要的功能。wget的压缩包里面已经自带了OpenSSL的库文件。
代码示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 bool bRet = false ; QStringList args; args << "--no-check-certificate" << "-c" << "-O" << "wechat.exe" << m_url; connect (m_pWgetProcess, &QProcess::readyReadStandardOutput, [&]() { while (m_pWgetProcess->bytesAvailable () > 0 ) { QString text = m_pWgetProcess->readLine (); QRegExp reg ("[\\s0-9K]+[\\.\\s]+([0-9]{1,3})%\\s+([0-9\\.]+[KM])\\s+([0-9hms]+).*" ); reg.setCaseSensitivity (Qt::CaseInsensitive); if (reg.exactMatch (text)) { int progress = reg.cap (1 ).toInt (); QString curSize = reg.cap (2 ).toLocal8Bit (); QString time = reg.cap (3 ).toLocal8Bit (); emit s_UpdateProgress (progress, time); } else if (text.contains ("100%" )) { emit s_UpdateProgress (100 , "0s" ); } else if (text.contains ("saved" ) && text.contains (QString ("[%1/%2]" ).arg (m_iFileSize).arg (m_iFileSize))) { emit s_haveDone (); } } }); connect (m_pWgetProcess, &QProcess::readyReadStandardError, [&]() { qWarning () << m_pWgetProcess->readAllStandardError (); emit s_haveError (2 , m_pWgetProcess->readAllStandardError ()); }); m_pWgetProcess->setReadChannel (QProcess::StandardOutput); m_pWgetProcess->setProcessChannelMode (QProcess::MergedChannels); m_pWgetProcess->start (m_wgetFilePath, args); bRet = m_pWgetProcess->waitForFinished (-1 ); if (!bRet) { qDebug () << m_pWgetProcess->errorString (); emit s_haveError (2 , m_pWgetProcess->errorString()) ; }
要点   上述代码非常简单,采用wget下载一个微信程序,实时通知下载进度并通知下载失败或完成,需要注意以下几点:
QProcess启动子进程推荐使用cmd和args分离的形式,适合参数比较复杂的情况
需要获取QProcess输出的时候,一般只读StandardOutput通道即可,StandardErro通道会有无意义的错误返回输出,导致解析难度加大
start方式启动的子进程需要调用waitForFinished或其他wait接口才能获取到输出,默认是阻塞30s,如果任务超时就会自动退出。需要等待子进程自己退出那么需要将参数传入-1。
在获取输出时采用readLine()按行读取解析时,如果输出过于庞大,会出现输出还没有获取完,但是子进程已经退出了(注意此时QProcess其实已经获取了全部输出在缓存里面了,在wait接口后面可以readAll获取到,但是我们是希望在QProcess::readyReadStandardOutput的槽函数里面同步处理)。这里就可以采用while循环的方式,将全部输出全部按行解析。