上一次写了一篇多线程拷贝文件夹的文章,这次世界使用线程池吧,使用线程池可以避免创建和销毁线程的开销,效率进一步提升。
先看看效果,这里展示的是终端版本的程序。
main.cpp:
//author:autumoon
//联系QQ:4589968
//日期:2021-07-01
#include <QCoreApplication>
#include <QDir>
#include "poolmanager.h"
int getFiles(const QString& strDir, QStringList& lPathNames, QString strSuffix = "*.*", bool bIncludeSub = true);
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
if (argc < 3)
{
printf("usage: poolcopy $src_dir &dst_dir $thread_count");
return -1;
}
QThread worker_thread_;
QString strSrcDir = argv[1];
QString strDstDir = argv[2];
if(strSrcDir.length() && strDstDir.length())
{
QStringList lSrcFiles, lDstFiles;
int n = getFiles(strSrcDir, lSrcFiles);
for (int i = 0; i < n; ++i)
{
//得到目标路径
QString strCurFile = lSrcFiles[i];
QString strDstFile = strCurFile;
strDstFile.replace(strSrcDir, strDstDir);
lDstFiles.push_back(strDstFile);
}
int max_thread = 4;
if(argc >=4)
{
max_thread = atoi(argv[3]);
if (max_thread <= 0)
{
max_thread = 4;
}
}
//线程池
PoolManager* manager = new PoolManager(max_thread);
manager->moveToThread(&worker_thread_);
worker_thread_.start();
manager->PoolCopyFiles(lSrcFiles, lDstFiles);
}
return a.exec();
}
QString LeftSuffixOnly(QString strPathOrFilter, bool bToLower /*= false*/)
{
if (strPathOrFilter.isEmpty() || strPathOrFilter.endsWith('/')) return strPathOrFilter;
//没有后缀
int nLastPointIndex = strPathOrFilter.lastIndexOf('.');
if (nLastPointIndex == -1)
{
return "";
}
strPathOrFilter = strPathOrFilter.right(strPathOrFilter.length() - nLastPointIndex - 1);
if (bToLower)
{
strPathOrFilter = strPathOrFilter.toLower();
}
return strPathOrFilter;
}
int getFiles(const QString &strDir, QStringList& lPathNames, QString strSuffix, bool bIncludeSub)
{
//此处修改遍历文件夹地址
QDir d(strDir);
//列出文件,列出隐藏文件(在Unix下就是以.开始的为文件),不列出符号链接(不支持符号连接的操作系统会忽略)
d.setFilter(QDir::Files | QDir::Hidden | QDir::NoSymLinks | QDir::AllDirs | QDir::NoDotAndDotDot);
//按文件大小排序,相反的排序顺序
//d.setSorting(QDir::Size | QDir::Reversed);
QStringList nameFilters;
QString strOnlySuffix = LeftSuffixOnly(strSuffix, true);
nameFilters << "*." + strOnlySuffix;
QFileInfoList list = d.entryInfoList();//返回这个目录中所有目录和文件的QFileInfo对象的列表
while(!list.isEmpty())
{
QFileInfo tem= list.last();
if(tem.isFile())
{
QString strPath = tem.filePath();
QString strFileSuffix(strPath);
if (strOnlySuffix == "*" || LeftSuffixOnly(strFileSuffix, true) == strOnlySuffix.toLower())
{
lPathNames.push_back(strPath);
}
list.pop_back();
}
else if (tem.isDir() && tem.fileName() != "." && tem.fileName() != ".." && bIncludeSub)
{
QDir a(tem.filePath());
a.setFilter(QDir::Files | QDir::Hidden | QDir::NoSymLinks | QDir::AllDirs | QDir::NoDotAndDotDot);
list.pop_back();
list.append(a.entryInfoList());
}
else
{
list.pop_back();
}
}
return lPathNames.size();
}
poolmanager.h:
#ifndef POOLMANAGER_H
#define POOLMANAGER_H
#include <QObject>
#include <QThreadPool>
#include <QMutex>
class PoolManager : public QObject
{
Q_OBJECT
public:
explicit PoolManager(int nMaxThreadCount = 4);
~PoolManager();
public slots:
void PoolCopyFiles(const QStringList& lSrcFiles, const QStringList& lDstFiles);
signals:
//第几个,总数,源文件
void progress(qint64, qint64, QString);
private slots:
void finished_file(bool bSuccess, QString strSrcFilePath);
private:
QThreadPool thread_pool_;
int m_nFileCount;
int m_nCurIndex;
};
#endif // POOLMANAGER_H
poolmanager.cpp:
#include "poolmanager.h"
#include "taskworker.h"
PoolManager::PoolManager(int nMaxThreadCount /*= 4*/)
{
if (nMaxThreadCount > 0 && nMaxThreadCount <= 100)
{
thread_pool_.setMaxThreadCount(nMaxThreadCount);
}
m_nFileCount = 0;
m_nCurIndex = 0;
}
PoolManager::~PoolManager()
{
}
void PoolManager::PoolCopyFiles(const QStringList &lSrcFiles, const QStringList &lDstFiles)
{
m_nCurIndex = 0;
m_nFileCount = qMin(lSrcFiles.size(), lDstFiles.size());
for (int i = 0; i < m_nFileCount; ++i)
{
QString strSrcFilePath = lSrcFiles[i];
QString strDstFilePath = lDstFiles[i];
TaskWorker* worker = new TaskWorker;
connect(worker, SIGNAL(finished(bool, QString)), this, SLOT(finished_file(bool, QString)));
worker->setSrcFilePath(strSrcFilePath)->setDstFilePath(strDstFilePath);
thread_pool_.start(worker);
}
}
void PoolManager::finished_file(bool bSuccess, QString strSrcFilePath)
{
Q_UNUSED(bSuccess)
emit progress(++m_nCurIndex, m_nFileCount, strSrcFilePath);
printf("%d / %d %s\n", m_nCurIndex, m_nFileCount, strSrcFilePath.toUtf8().data());
}
taskworker.h
#ifndef TASKWORKER_H
#define TASKWORKER_H
#include <QObject>
#include <QRunnable>
class TaskWorker : public QObject,public QRunnable
{
Q_OBJECT
public:
void run();
TaskWorker* setSrcFilePath(const QString& strSrcFilePath)
{
m_strSrcFilePath = strSrcFilePath;
return this;
}
TaskWorker* setDstFilePath(const QString& strDstFilePath)
{
m_strDstFilePath = strDstFilePath;
return this;
}
signals:
void finished(bool, QString);
protected:
QString m_strSrcFilePath;
QString m_strDstFilePath;
};
#endif // TASKWORKER_H
taskworker.cpp
#include "taskworker.h"
#include <QFile>
#include "../Common/Log.h"
#include "../Common/StdDirFile.h"
void TaskWorker::run()
{
//拷贝文件
if (!QFile::exists(m_strSrcFilePath))
{
emit finished(false, m_strSrcFilePath);
CLOG::Out(m_strSrcFilePath + " 文件不存在! ");
return;
}
if (QFile::exists(m_strDstFilePath) && !CStdDir::DeleteFileOrFolder(m_strDstFilePath))
{
CLOG::Out(m_strDstFilePath + " 文件已存在并且被占用! ");
emit finished(false, m_strSrcFilePath);
return;
}
CStdDir::createDirectory(m_strDstFilePath, true);
QFile source(m_strSrcFilePath);
QString dest = m_strDstFilePath;
bool bRes = true;
if (!source.copy(dest))
{
bRes = false;
CLOG::Out(m_strSrcFilePath + " -> " + m_strDstFilePath + "复制失败! 错误原因:" + source.errorString());
}
emit finished(bRes, m_strSrcFilePath);
}
欢迎交流与讨论。