【QML】QML复制文件或文件夹,显示进度,多线程复制

1. 效果

  • 可以显示复制文件文件夹的进度
    在这里插入图片描述
  • 复制文件: bool copyFileFunc(QString _from, QString _to);
  • 复制文件夹:bool copyDirectoryFiles(const QString &_from, const QString &_to);
  • 举例:
	//复制文件
    copyhelper.copyFileToDir("./test.txt", "d:/copytest/dir/test1.txt");
    
    //复制文件夹
    copyhelper.copyFileToDir("./copyTest", "d:/copytest/dir/copyTest1");

2. QML代码

import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15
import QtQuick.Controls.Styles 1.4
import QtQuick.Controls 1.4

Window {
    width: 640
    height: 480
    visible: true
    title: qsTr("copy file")

    Rectangle{
        id: _progress
        width: parent.width
        height: parent.height / 2
        border.color: "blue"
        border.width: 1
        property string processv: "0"

        ProgressBar {
            id: pbar
            width: 480;
            height: 30
            minimumValue:  0
            maximumValue:  100
            value: 0
            anchors.centerIn: parent

            style: ProgressBarStyle{
                id: progressStyle

                background: Rectangle{
                    color: "lightgrey"
                    radius: 6
                }
                progress: Rectangle{
                    color: control.value === 100 ? "#b1d946" :"#4c7aff"
                    radius: 6
                }

                panel: Item{
                    //通过panel属性,可以加载  progress Text background等组件
                    //设置外边框
                    implicitWidth: 480;
                    implicitHeight: 15;

                    Loader{
                        anchors.fill:  parent;
                        sourceComponent: background;
                    }

                    Loader{
                        id: progressLoader;
                        anchors.top: parent.top;
                        anchors.left: parent.left;
                        anchors.bottom:  parent.bottom;
                        anchors.margins: 0;
                        z: 1;
                        width: currentProgress * (parent.width);
                        sourceComponent: progressStyle.progress;
                    }

                    Text{
                        color: "black"
                        text: _progress.processv
                        z: 2
                        anchors.centerIn: parent
                    }
                }
            }
        }
    }


    Button{
        width: 200
        height: 100
        anchors.top: _progress.bottom
        anchors.horizontalCenter: _progress.horizontalCenter
        anchors.topMargin: 20
        text: qsTr("开始复制")

        onClicked: {
            console.log("开始复制")
            //复制文件
            //copyhelper.copyFileToDir("./test.txt", "d:/copytest/dir/test1.txt");
            //复制文件夹
            copyhelper.copyFileToDir("./copyTest", "d:/copytest/dir/copyTest1");
        }
    }

    Connections{
        target: copyhelper

        function onQmlCopyProgress(value){
            pbar.value = value;
            _progress.processv =  value + "%";
        }
    }
}

3. main.c代码

#include <QGuiApplication>
#include <QtQml>
#include <QApplication>
#include <QQmlApplicationEngine>
#include "copyhelper.h"


int main(int argc, char *argv[])
{
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif
    QApplication app(argc, argv);

    QQmlApplicationEngine engine;

    engine.rootContext()->setContextProperty("copyhelper", new CopyHelper);

    const QUrl url(QStringLiteral("qrc:/main.qml"));
    QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
        &app, [url](QObject *obj, const QUrl &objUrl) {
            if (!obj && url == objUrl)
                QCoreApplication::exit(-1);
        }, Qt::QueuedConnection);
    engine.load(url);

    return app.exec();
}

4. .pro代码

QT += quick qml widgets core

# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

SOURCES += \
        copyfiles.cpp \
        copyhelper.cpp \
        main.cpp

RESOURCES += qml.qrc

# Additional import path used to resolve QML modules in Qt Creator's code model
QML_IMPORT_PATH =

# Additional import path used to resolve QML modules just for Qt Quick Designer
QML_DESIGNER_IMPORT_PATH =

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

HEADERS += \
    copyfiles.h \
    copyhelper.h

5. C++代码

  • 创建两个类 CopyHelperCopyFiles
  • CopyFiles中是具体实现
  • CopyHelper 为了实现多线程

5.1 copyfile.h

#ifndef COPYFILES_H
#define COPYFILES_H

#include <QObject>
#include <QDebug>
#include <QFile>        //文件操作
#include <QDataStream>  //数据流
#include <QThread>      //线程

class CopyFiles : public QObject
{
    Q_OBJECT
public:
    //只能显式构造
    /**
     *  QString _srcFilePath    : 源文件路径
     *  QString _dstPath        : 目标路径
     *  QObject *parent = 0     : 父对象指针,默认为空
    */
    explicit CopyFiles(QString _srcFilePath, QString _dstPath,QObject *parent = 0);

signals:
    void startCopyFile(QString, QString);   //复制文件信号
    void startCopyDir(QString, QString);    //复制文件夹信号
    void copyProcess(QString);              //复制文件进度信号

public slots:
    /**
     * @brief copyFileFunction : 复制文件信号处理槽
     * @param _from : 源文件名
     * @param _to   : 目标文件名
     * @return bool : 返回类型 成功返回true 失败返回false
    */
    bool copyFileFunc(QString _from, QString _to);

    /**
     * @brief copyDirectoryFiles : 复制文件夹
     * @param _from : 源文件夹路径
     * @param _to   : 目标文件夹路径
     * @return  : 成功返回true 失败返回false
     */
    bool copyDirectoryFiles(const QString &_from, const QString &_to);

private:
    bool m_firstRead = true;
    qint64 m_total = 0;
    qint64 m_now = 0;

private:
    void getDirSize(QString _dir, qint64* size);
    bool copyFile(QString _from, QString _to, qint64* nowSize, qint64 totalSize);
};

#endif // COPYFILES_H

5.2 copyfile.cpp

#include "copyfiles.h"
#include "qfileinfo.h"
#include <QFile>
#include <QDir>

CopyFiles::CopyFiles(QString _srcFilePath, QString _dstPath, QObject *parent)
{
    qDebug() << QThread::currentThreadId() << _srcFilePath << _dstPath;
}


bool CopyFiles::copyFileFunc(QString _from, QString _to)
{
    qint64 fileSize = 0;
    qint64 totalCopySize = 0;

    //文件夹创建
    QFileInfo fininfo(_to);
    QDir path;
    if(!path.exists(fininfo.absolutePath())){
        path.mkdir(fininfo.absolutePath());
    }

    //文件对象
    QFile tofile;
    tofile.setFileName(_to);
    QFile fromfile;
    fromfile.setFileName(_from);
    fileSize = fromfile.size();

    /* 复制文件 */
    return copyFile(_from, _to, &totalCopySize, fileSize);
}

bool CopyFiles::copyDirectoryFiles(const QString &_from, const QString &_to)
{
    QDir sourceDir(_from);
    QDir targetDir(_to);

    qDebug() << "copy form" <<_from << _to;

    /* 如果目录不存在,则创建 */
    if(!targetDir.exists()){
        if(!targetDir.mkdir(targetDir.absolutePath())){
            return false;
        }
    }

    QFileInfoList fileInfoList = sourceDir.entryInfoList();
    if(m_firstRead){
        qDebug() << "copyDirectoryFiles count:" << fileInfoList.count();

        /* 获取文件夹总大小 */
        m_total = 0;
        getDirSize(_from, &m_total);

        /* 标志位 */
        m_now = 0;
        m_firstRead = false;
        qDebug() << "copyDirectoryFiles: " << m_total << m_now;

        /* 复制完成 */
        if(m_now == m_total){
            m_firstRead = true;
        }
    }

    foreach(QFileInfo fileInfo, fileInfoList){
        if(fileInfo.fileName() == "." || fileInfo.fileName() == ".."){
            continue;
        }

        /* 当前为目录递归进行copy */
        if(fileInfo.isDir()){
            if(!copyDirectoryFiles(fileInfo.filePath(), targetDir.filePath(fileInfo.fileName()))){
                return false;
            }
        }
        /* 复制文件 */
        else{
            if(!copyFile(fileInfo.filePath(), targetDir.filePath(fileInfo.fileName()), &m_now, m_total)){
                return false;
            }
        }
    }

    return true;
}

void CopyFiles::getDirSize(QString _dir, qint64* size)
{
    QDir sourceDir(_dir);
    QFileInfoList fileInfoList = sourceDir.entryInfoList();

    /* 遍历文件夹 */
    foreach(QFileInfo fileInfo, fileInfoList){
        if(fileInfo.isFile()){
            if(fileInfo.fileName() != "." && fileInfo.fileName() != ".."){
                *size += fileInfo.size();
                qDebug() << "1-----" << fileInfo.fileName() << *size;
            }
        }else if(fileInfo.isDir()){
            /* 递归 */
            if(fileInfo.fileName() != "." && fileInfo.fileName() != ".."){
                getDirSize(fileInfo.filePath(), size);
                qDebug() << "2-----" << fileInfo.fileName() <<fileInfo.filePath();
            }
        }
    }
}

bool CopyFiles::copyFile(QString _from, QString _to, qint64* nowSize, qint64 totalSize)
{
    qDebug() << "子线程ID:" << QThread::currentThreadId();

    char * byteTemp = new char[1024*8]; //每次复制8k
    qint64 fileSize = 0;
    qint64 totalCopySize = 0;

    //文件夹创建
    QFileInfo fininfo(_to);
    QDir path;
    if(!path.exists(fininfo.absolutePath())){
        path.mkdir(fininfo.absolutePath());
    }

    //文件对象
    QFile tofile;
    tofile.setFileName(_to);
    QFile fromfile;
    fromfile.setFileName(_from);

    //文件读取判断
    if(!tofile.open(QIODevice::WriteOnly))
    {
        qDebug() << "无法打开目标文件1";
        delete[](byteTemp);
        return false;
    }
    if(!fromfile.open(QIODevice::ReadOnly)){
        qDebug() << "无法打开目标文件2";
        delete[](byteTemp);
        return false;
    }

    //文件大小
    QDataStream out(&tofile);//文件流
    out.setVersion(QDataStream::Qt_4_0);
    fileSize = fromfile.size();
    QDataStream in(&fromfile);
    in.setVersion(QDataStream::Qt_4_0);
    qDebug() << "文件总大小:" << fileSize << " / " << QString::number(totalSize);

    //循环复制文件
    while(!in.atEnd())
    {
        qint64 readSize = 0;

        //每次读取8k
        readSize = in.readRawData(byteTemp, 1024*8);    //读取复制文件到缓存并返回读取的实际大小
        out.writeRawData(byteTemp, readSize);           //写到输出流
        totalCopySize += readSize;                      //累计已复制大小
        *nowSize += readSize;
        int tmpVal = *nowSize / (double)totalSize * 100;//复制进度计算
        emit copyProcess(QString::number(tmpVal));      //发射当前复制进度
        //qDebug() << "now:" << *nowSize;
    }

    //复制完成
    if(totalCopySize == fileSize){
        tofile.setPermissions(QFile::ExeUser);//设置文件权限
        tofile.close();     //关闭文件流
        fromfile.close();   //关闭文件流
        delete[](byteTemp);
        return true;        //返回复制结果-成功
    }else{
        delete[](byteTemp);
        return false;       //返回复制结果-失败
    }
}



5.3 copyhelper.h

#ifndef COPYHELPER_H
#define COPYHELPER_H

#include <QObject>


class CopyHelper : public QObject
{
    Q_OBJECT
public:
    explicit CopyHelper(QObject *parent = 0);

public:
    /**
      * @brief copyFileToDir 复制文件到目录
      * @return QString 返回字符串
    */
    Q_INVOKABLE QString copyFileToDir(QString _from, QString _to);

signals:
    /**
     * @brief qmlCopyProgress 供qml使用的复制文件进度信号
     * @param value
     */
    void  qmlCopyProgress(QString value);

private :
    /**
     * @brief testReadFile 测试读取文件
     */
    void testReadFile();

private slots:
    /**
      * @brief reciveCopyProgress 接收文件进度槽
      */
    void reciveCopyProgress(QString);
};

#endif // COPYHELPER_H

5.4 copyhelper.cpp

#include "copyhelper.h"
#include <QDebug>
#include <QFile>
#include <QDataStream>
#include <QThread>
#include <QFileInfo>
#include "copyfiles.h"

CopyHelper::CopyHelper(QObject *parent) : QObject(parent)
{
    qDebug() << "文件复制助手线程ID:" <<QThread::currentThreadId();
}

//复制文件到目录
QString CopyHelper::copyFileToDir(QString _from, QString _to)
{
    //构造复制文件类
    CopyFiles * m_pCopyFile = new CopyFiles(_from, _to);

    //复制文件子线程
    QThread * m_pCopyFilethread =  new QThread();
    m_pCopyFile->moveToThread(m_pCopyFilethread); //子线程中执行文件复制

    //连接文件复制信号
    connect(m_pCopyFile,SIGNAL(startCopyFile(QString,QString)),m_pCopyFile,SLOT(copyFileFunc(QString,QString)));
    connect(m_pCopyFile,SIGNAL(startCopyDir(QString,QString)),m_pCopyFile,SLOT(copyDirectoryFiles(QString,QString)));
    connect(m_pCopyFile,SIGNAL(copyProcess(QString)),this,SLOT(reciveCopyProgress(QString)));

    //链接线程完成信号
    connect(m_pCopyFilethread, SIGNAL(finished()), m_pCopyFilethread, SLOT(deleteLater()));
    connect(m_pCopyFilethread, &QThread::finished, m_pCopyFilethread, &QObject::deleteLater);

    //启动复制线程
    m_pCopyFilethread->start();

    //判断文件还是文件夹
    QFileInfo fileInfo(_from);
    if(fileInfo.isDir()){
        //发射文件夹复制开始信号
        emit m_pCopyFile->startCopyDir(_from, _to);
    }else{
        //发射文件复制开始信号
        emit m_pCopyFile->startCopyFile(_from, _to);
    }

    return "复制成功";
}

//测试读取文件
void CopyHelper::testReadFile()
{
    //测试复制文件
    QString strFileName = "d:/test.rar";
    if (!QFile::exists(strFileName)){return;} //文件不存在

    QFile file(strFileName);
    if (!file.open(QFile::ReadOnly)){return;}//文件无法打开

    QDataStream in(&file);      //数据流
    int nFileSize = file.size();//文件大小
    int p = 0;                  //当前复制位置

    while (!in.atEnd()) {
        char buffer [8192];
        int readsize = 0;

        readsize = in.readRawData(buffer,8192);
        p = file.pos();
        qDebug() <<"文件总大小:"<<nFileSize<<"读取大小"<<readsize<<" 当前复制进度"<<QString::number(p);
    }
}

//接收文件进度
void CopyHelper::reciveCopyProgress(QString value)
{
    emit qmlCopyProgress(value);//发射接收文件进度
}

6. 参考

  • QML复制文件并显示进度
  • Qt制作有进度条的拷贝文件夹和文件的小Demo

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/258584.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

手机技巧:手机膜种类介绍,你真的了解吗

目录 一、材质分类 水凝膜 钢化玻璃膜 二、功能分类 抗蓝光膜 防窥膜 磨砂膜 三、最后 鉴于智能手机越来越“娇贵”的体质&#xff0c;能让手机“裸奔”的大神相信不在多数。 然而比较注重手机保养的朋友都会选择给手机贴膜&#xff0c;这样能防止手机刮划&#xff0c;…

数据结构--图(更新ing~)

树具有灵活性&#xff0c;并且存在许多不同的树的应用&#xff0c;但是就树本身而言有一定的局限性&#xff0c;树只能表示层次关系&#xff0c;比如父子关系。而其他的比如兄弟关系只能够间接表示。 推广--- 图 图形结构中&#xff0c;数据元素之间的关系是任意的。 一、图…

Java:语法速通

参考 菜鸟教程 java 继承 class 父类 { }class 子类 extends 父类 { }继承的特性&#xff1a; 子类拥有父类非private的属性和方法子类可以对父类进行扩展子类可以重写父类的方法使用extends只能单继承&#xff0c;使用implements可以变相的多继承&#xff0c;即一个类继承…

24_28-Golang函数详解

**Golang **函数详解 主讲教师&#xff1a;&#xff08;大地&#xff09; 合作网站&#xff1a;www.itying.com** **&#xff08;IT 营&#xff09; 我的专栏&#xff1a;https://www.itying.com/category-79-b0.html 1、函数定义 :::info 函数是组织好的、可重复使用的、用…

雪花算法(几种常见的雪花算法生成ID方案简单介绍:Hutool、百度Uid-Generator、美团Leaf、Yitter)

文章目录 1.生成id的几种方式2. 雪花算法2.1 雪花算法介绍2.2 市面上几种雪花算法的实现2.2.1 hutool版2.2.1.1 hutool版本雪花算法 关于时钟回拨的处理&#xff1a; ---------------百度UidGenerator 介绍开始--------------2.2.2 百度版&#xff1a;[UidGenerator](https://g…

vue 流光边框矩形圆形容器

实现流光边框一般是用渐变背景加动画实现&#xff0c;然后使用内部盒子遮挡内部空间&#xff0c;达到边框流光的效果 思路&#xff1a;背景渐变旋转动画 功能&#xff1a; 自定义渐变&#xff08;是否渐变<不渐变没有流光效果>&#xff0c;渐变颜色&#xff0c;渐变角…

鉴赏 tcp vegas

优秀的 vegas 之后&#xff0c;再鉴赏一下迄今唯一像那么回事的拥塞控制算法 vegas。 从下图可看出所有的(对&#xff0c;所有的) aimd 都毫无伸缩性(z:吞吐&#xff0c;x:rtt&#xff0c;y:丢包率&#xff0c;由 buffer_size 直接决定)&#xff1a; 一下就可看出 rtt 和 bu…

LeetCode day27

LeetCode day27 —今天做到树&#xff0c;&#xff0c;&#xff0c;对不起我的数据结构老师啊~~~ 7. 整数反转 给你一个 32 位的有符号整数 x &#xff0c;返回将 x 中的数字部分反转后的结果。 如果反转后整数超过 32 位的有符号整数的范围 [−231, 231 − 1] &#xff0c…

springboot跨域问题,解决方法

前端访问出现CORS跨域问题 不多说&#xff0c;直接上代码~ import org.springframework.stereotype.Component;import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException;Component…

OpenAI 偷偷在训练 GPT-4.5!?

最近看到有人已经套路出 ChatGPT 当前的版本&#xff0c;回答居然是 gpt-4.5-turbo&#xff1a; 实际试验下&#xff0c;用 starflow.tech&#xff0c;切换到小星 4 全能版&#xff08;同等官网最新 GPT-4&#xff09;&#xff0c;复制下面这段话问它&#xff1a; What is the…

winfrom大恒工业相机SDK二次开发、C#联合halcon开发

一、开发环境 1.在大恒图像官网下载SDK安装包&#xff0c;安装SDK后&#xff0c;打开安装目录找到Samples文件夹&#xff0c;然后找到Samples\CSharp SDK\x64\DoNET\.NET4.0文件夹下找到GxIAPINET.dll&#xff0c;如图&#xff1a; 2.打开VS2019软件&#xff0c;建立winfrom项…

JS中的异常处理:

throw: 抛出异常时我们哪个关键字&#xff1f;它会终止程序&#xff1f; throw关键字 会终止程序 抛出异常经常和谁配合使用&#xff1f; Error对象配合throw使用 代码演示&#xff1a; function fn(x,y){if(!x || !y){// console.log(11);// throw 用户没有参数传递进来;th…

【BEV感知】BEVFormer 融合多视角图形的空间特征和时序特征 ECCV 2022

前言 本文分享BEV感知方案中&#xff0c;具有代表性的方法&#xff1a;BEVFormer。 它基于Deformable Attention&#xff0c;实现了一种融合多视角相机空间特征和时序特征的端到端框架&#xff0c;适用于多种自动驾驶感知任务。 主要由3个关键模块组成&#xff1a; BEV Que…

EasyExcel合并相同内容单元格及动态标题功能的实现

一、最初版本 导出的结果&#xff1a; 对应实体类代码&#xff1a; import com.alibaba.excel.annotation.ExcelProperty; import com.alibaba.excel.annotation.write.style.ColumnWidth; import com.alibaba.excel.annotation.write.style.ContentLoopMerge; import com.al…

markdown文档主题颜色修改

目录 1、选择任意想选择的markdown文档主题css文件&#xff1a; 2、修改背景颜色 1、选择任意想选择的markdown文档主题css文件&#xff1a; 使用工具Typora文件主题路径&#xff1a; C:\Users\AppData\Roaming\Typora\themes&#xff0c;此处我这边就是copy了xydark的css文…

Java 自定义注解

Java 自定义注解&#xff0c; 以及interface Target Retention Around Before After ProceedingJoinPoint JoinPoint 等用法 注解应用非常广泛&#xff0c;我们自定义注解能简化开发各种各种业务 一、关键字解释 (1) 定义注解时&#xff0c;关键字 interface 来表示注解类的类…

高级算法设计与分析(二) -- 递归与分治策略

系列文章目录 高级算法设计与分析&#xff08;一&#xff09; -- 算法引论 高级算法设计与分析&#xff08;二&#xff09; -- 递归与分治策略 高级算法设计与分析&#xff08;三&#xff09; -- 动态规划 未完待续【 高级算法设计与分析&#xff08;四&#xff09; -- 贪…

谷歌新款 Pixel 8 更小、更智能!

一、谷歌 Pixel 8 更小、更智能——比去年的 Pixel 7 贵了 100 美元——不是一点点——贵 与 Pixel 7 一样&#xff0c;Pixel同样在今天 8 比正式发布的更大的 Pixel 8 Pro 兄弟产品更小、更便宜。但今年价格有所上涨&#xff0c;128GB 存储型号的 Pixel 8 起售价为 699.99 美…

腾讯云消息队列11月产品月报 | RocketMQ 5.x 国际站上线

2023年 11月动态 消息队列 RocketMQ 版 1、5.x 形态国际站上线 国际站上线 5.x 集群全系列&#xff0c;第一批先开放新加坡和硅谷地域。 控制台链接&#xff1a;https://console.tencentcloud.com/trocketmq 2、 无感迁移能力 支持用户白屏化操作&#xff0c;将自建的 Roc…

夜莺项目发布 v6.5.0 版本,暗黑菜单来了

大家好&#xff0c;夜莺项目发布 v6.5.0 版本&#xff0c;启用新 logo&#xff0c;菜单支持换肤&#xff0c;支持了暗黑版本的菜单&#xff0c;下一步会支持全站暗黑主题&#xff0c;敬请期待&#xff0c;下面是新 logo。 暗黑菜单 页面右上角点击用户名&#xff0c;在下拉框里…