有个需求就是,GUI图形界面在上传文件到服务器的时候,需要用zip命令行打包,因为文件很多的时候,zip命令打包需要计算很长时间,所以把这样计算量大的任务分离到后台线程比较合适,然后任务完成,以信号槽机制来通知前台
UI线程处理结果。所以这个线程是需要销毁的,跟之前的一直在运行的后台线程接收网络数据的不一样。
压缩文件的任务类 H文件:
#include <QObject>
#include <QStringList> class ZipUpdatePackageTask : public QObject
{
Q_OBJECT public:
ZipUpdatePackageTask();
~ZipUpdatePackageTask(); public slots:
void doZip();
void beZipFiles(const QStringList& files);
signals:
void zipFinished();
void zipPackageInfo(const QString& fileName, const QString& md5, const QString& size); private:
bool beZipFilesIsEmpty();
void deleteHistoryZip(const QString& targetPackage);
void toBeZipFilesArguments(QString &files);
void startZipTask(QString zipExePath, QString targetPackage, QString files);
QString getFileMD5(const QString& targetZipPackage);
QString getFileSize(const QString& targetZipPackage);
private:
QStringList m_files;
};
压缩任务类的 cpp文件:
#include <QCoreApplication>
#include <QFile>
#include <QFileInfo>
#include <QDir>
#include <QProcess>
#include <QCryptographicHash> ZipUpdatePackageTask::ZipUpdatePackageTask()
{
} ZipUpdatePackageTask::~ZipUpdatePackageTask()
{
} void ZipUpdatePackageTask::doZip()
{
QString appDir = qApp->applicationDirPath();
QString zipExePath = QString("%1/%2").arg(appDir).arg("zip.exe");
if (QFile::exists(zipExePath) && !beZipFilesIsEmpty())
{ QString targetZipPackage = QString("%1/%2").arg(appDir).arg("update.zip");
QString beZipFiles; toBeZipFilesArguments(beZipFiles);
deleteHistoryZip(targetZipPackage);
startZipTask(zipExePath, targetZipPackage, beZipFiles); if (QFile::exists(targetZipPackage))
{
QString size = getFileSize(targetZipPackage);
QString md5 = getFileMD5(targetZipPackage); emit zipPackageInfo(targetZipPackage, md5, size); } } emit zipFinished();
} void ZipUpdatePackageTask::beZipFiles(const QStringList& files)
{
m_files.clear();
m_files = files;
} bool ZipUpdatePackageTask::beZipFilesIsEmpty()
{
return m_files.isEmpty();
} void ZipUpdatePackageTask::deleteHistoryZip(const QString& targetPackage)
{
if (QFile::exists(targetPackage))
{
QDir dir;
dir.remove(targetPackage);
}
} void ZipUpdatePackageTask::toBeZipFilesArguments(QString &files)
{
for (auto file : m_files)
{
files.append(file);
files.append(" ");
}
} void ZipUpdatePackageTask::startZipTask(QString zipExePath, QString targetPackage, QString files)
{
QProcess* zipProcesss = new QProcess;
//zip a [zip_package_path_name] [file1Path]...[fileNPath]
QString command = QString("%1 a %2 %3").arg(zipExePath).arg(targetPackage).arg(files);
zipProcesss->start(command);
zipProcesss->waitForFinished(-);
} QString ZipUpdatePackageTask::getFileMD5(const QString& targetZipPackage)
{
QString md5;
QFile file(targetZipPackage);
if (file.open(QFile::ReadOnly))
{
QCryptographicHash hash(QCryptographicHash::Md5);
if (hash.addData(&file))
{
md5 = QString(hash.result().toHex());
} file.close();
}
return md5;
} QString ZipUpdatePackageTask::getFileSize(const QString& targetZipPackage)
{
QFileInfo fileInf(targetZipPackage);
return QString::number(fileInf.size());
}
以下是创建这个后台压缩线程的槽函数,当压缩上传的button点击,就调用以下这个槽函数:
void StatisticsWidget::slotUploadPackage()
{
QThread *zipThread = new QThread;
ZipUpdatePackageTask* task = new ZipUpdatePackageTask(); QStringList beZipFiles;
for (int listRow = ; listRow < ui->updateFileList->count(); ++listRow)
{
beZipFiles << ui->updateFileList->item(listRow)->text();
} task->beZipFiles(beZipFiles);
task->moveToThread(zipThread); connect(zipThread, &QThread::started, task, &ZipUpdatePackageTask::doZip); connect(task, SIGNAL(zipFinished()), zipThread, SLOT(quit()));
connect(task, &ZipUpdatePackageTask::zipPackageInfo, this, &StatisticsWidget::slotZipFinished,Qt::QueuedConnection); //automatically delete thread and task object when work is done:
connect(zipThread, SIGNAL(finished()), task, SLOT(deleteLater()));
connect(zipThread, SIGNAL(finished()), zipThread, SLOT(deleteLater()));
zipThread->start();
}
注意,以上代码都是临时任务和线程,当任务完成以后,由于设置了相应的信号槽,会自动删除。 任务线程做完该做的事儿,发出了一个zipPackageInfo的信号就销毁了。UI线程只用编写一个槽函数来接收做完的信号并处理就可以了。