• 【Qt Demo】异步拷贝文件(可取消)


    效果


    核心代码

    由于 Qt 的中 QFile::copy 是个原子操作,所以并不支持拷贝文件进度。所以用 QThread 实现了在线程中拷贝文件,并能实时更新文件进度,主要代码封装在 FileCopyer 类里。(可以跨平台)

    FileCopyer.h

    #pragma once
    
    #include <QtCore/qstring.h>
    #include <QtCore/qobject.h>
    #include <QtCore/qfile.h>
    #include <QtCore/qfileinfo.h>
    #include <QtCore/qvector.h>
    #include <QtCore/qthread.h>
    
    class FileCopyer : public QObject {
        Q_OBJECT
            Q_PROPERTY(qint64 chunksize READ chunkSize WRITE setChunkSize)
            Q_PROPERTY(QVector<QString> sourcePaths READ sourcePaths WRITE setSourcePaths)
            Q_PROPERTY(QVector<QString> destinationPaths READ destinationPaths WRITE setDestinationPaths)
    
    public:
        static const int DEFAULT_CHUNK_SIZE = 1024 * 1024 * 1;
    
        FileCopyer(QThread*);
        ~FileCopyer();
    
        qint64 chunkSize() const {
            return _chunk;
        }
        void setChunkSize(qint64 ch) {
            _chunk = ch;
        }
    
        QVector<QString> sourcePaths() const {
            return src;
        }
        void setSourcePaths(const QVector<QString>& _src) {
            src = _src;
        }
    
        QVector<QString> destinationPaths() const {
            return dst;
        }
        void setDestinationPaths(const QVector<QString>& _dst) {
            dst = _dst;
        }
    
        void interrupt()
        {
            _interrupt = true;
        }
    
        protected slots:
        void copy();
    
    
    
    private:
        QVector<QString> src, dst;
        qint64 _chunk;
        bool _interrupt;
    
    signals:
        void copyProgress(qint64 bytesCopied, qint64 bytesTotal);
        void finished(bool success);
        void oneBegin(QString srcFileName);
        void oneFinished(QString dstPath, bool result);
    };
    
    

    FileCopyer.cpp

    #include <QtCore/qdebug.h>
    #include "FileCopyer.h"
    
    FileCopyer::FileCopyer(QThread* _thread) :QObject(nullptr),
        _interrupt(false){
        moveToThread(_thread);
        setChunkSize(DEFAULT_CHUNK_SIZE);
    
        QObject::connect(_thread, &QThread::started, this, &FileCopyer::copy);
        QObject::connect(this, &FileCopyer::finished, _thread, &QThread::quit);
        //QObject::connect(this, &FileCopyer::finished, this, &FileCopyer::deleteLater);
        QObject::connect(_thread, &QThread::finished, _thread, &QThread::deleteLater);
    }
    
    FileCopyer::~FileCopyer() {
    
    }
    
    void FileCopyer::copy()
    {
        if (src.isEmpty() || dst.isEmpty())
        {
            qWarning() << QStringLiteral("source or destination paths are empty!");
            emit finished(false);
            return;
        }
    
        if (src.count() != dst.count())
        {
            qWarning() << QStringLiteral("source or destination paths doesn't match!");
            emit finished(false);
            return;
        }
    
        qint64 total = 0, written = 0;
        for (const auto& f : src)
            total += QFileInfo(f).size();
        qInfo() << QStringLiteral("%1 bytes should be write in total").arg(total);
    
        int indx = 0;
        qInfo() << QStringLiteral("writing with chunk size of %1 byte").arg(chunkSize());
        while (indx < src.count())
        {
            const auto dstPath = dst.at(indx);
    
            QFile srcFile(src.at(indx));
            QFile dstFile(dstPath);
            if (QFile::exists(dstPath))
            {
                qInfo() << QStringLiteral("file %1 alreasy exists, overwriting...").arg(dstPath);
                QFile::remove(dstPath);
            }
    
            if (!srcFile.open(QFileDevice::ReadOnly))
            {
                qWarning() << QStringLiteral("failed to open %1 (error:%2)").arg(srcFile.fileName()).arg(srcFile.errorString());
                indx++;
                continue; // skip
            }
    
            if (!dstFile.open(QFileDevice::WriteOnly))
            {
                qWarning() << QStringLiteral("failed to open %1 (error:%2)").arg(dstFile.fileName()).arg(dstFile.errorString());
                indx++;
                continue; // skip
            }
            emit oneBegin(QFileInfo(srcFile).fileName());
            /* copy the content in portion of chunk size */
            qint64 fSize = srcFile.size();
            while (fSize) {
                if(_interrupt)
                {
                    emit finished(true);
                    return;
                }
                const auto data = srcFile.read(chunkSize());
                const auto _written = dstFile.write(data);
                if (data.size() == _written)
                {
                    written += _written;
                    fSize -= data.size();
                    emit copyProgress(written, total);
                }
                else
                {
                    emit oneFinished(dstPath, false);
                    qWarning() << QStringLiteral("failed to write to %1 (error:%2)").arg(dstFile.fileName()).arg(dstFile.errorString());
                    fSize = 0;
                    break; // skip this operation
                }
            }
    
            srcFile.close();
            dstFile.close();
            emit oneFinished(dstPath, true);
            indx++;
            qDebug() << QThread::currentThreadId();
        }
    
        if (total == written)
        {
            qInfo() << QStringLiteral("progress finished, %1 bytes of %2 has been written").arg(written).arg(total);
            emit finished(true);
        }
        else
        {
            emit finished(false);
        }
    }
    
    

    调用如下:

    auto local = new QThread;
    auto worker = new FileCopyer(local);
    QObject::connect(worker, &FileCopyer::finished, [](bool s) {
    	s ? qDebug() << "FINISHED" : qDebug() << "FAILED";
    });
    QObject::connect(worker, &FileCopyer::copyProgress, [](qint64 copy, qint64 total) {
    	qDebug() << QStringLiteral("PROGRESS => %1").arg(qreal(copy) / qreal(total) * 100.0);
    });
    worker->setSourcePaths(/* src-paths */); // e.g: ~/content/example.mp4
    worker->setDestinationPaths(/* dst-paths */); // e.g /usr/local/example.mp4
    local->start();
    

    GitHub下载地址

    下载地址为:https://github.com/confidentFeng/QtAppProject/tree/CopyFile


    参考:

    基于Qt的异步拷贝文件

    qt 拷贝文件设置进度条


  • 相关阅读:
    《C语言程序设计》指针篇<一>
    《算法竞赛入门经典》刘汝佳 C语言部分(前四章)“注解与习题” 之思索 -<1>
    程序设计第二次作业<2>
    程序设计第二次作业<1>
    第一次面向对象程序设计作业-大一下学期的自我目标
    android部署tensorflow
    vim操作
    跑groud truth的disparity
    tensorflow与android编译
    Ubuntu ndk环境变量配置
  • 原文地址:https://www.cnblogs.com/linuxAndMcu/p/13470366.html
Copyright © 2020-2023  润新知