基于Qt使用线程池实现文件夹拷贝

62 篇文章 8 订阅

上一次写了一篇多线程拷贝文件夹的文章,这次世界使用线程池吧,使用线程池可以避免创建和销毁线程的开销,效率进一步提升。

先看看效果,这里展示的是终端版本的程序。

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);
}

欢迎交流与讨论。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值