当前位置: 首页 > news >正文

QT中级(6)基于QT的文件传输工具(2)

QT中级(6)基于QT的文件传输工具(2)

  • 本文实现第一步
  • 1 新增功能
  • 2 运行效果
  • 3 实现思路
  • 4 源代码

实现这个文件传输工具大概需要那几步?

  1. 实现多线程对文件的读写
  2. 实现TCP客户端和服务端
  3. 实现网络传输

书接上回:QT中级(5)多线程读取一个文件,并在另一个文件夹中合成这个文件(1)

本文实现第一步

1 新增功能

  1. 增加线程暂停和取消功能
  2. 增加意外关闭软件,再次打开可以重新续传
  3. 增加对线程的析构

2 运行效果

在这里插入图片描述

3 实现思路

  1. 通过创建标识符,控制线程的开始、暂停、取消(结束)
//线程工作状态
enum class TransferState {None,Running,Paused,Canceled,Unexpected
};
  1. 增加配置文件,记住软件运行的状态和一些文件相关信息
static QString configFilePath; //配置文件路径
static QString sourceFilePath; //源文件路径
static QString targetFilePath; //目标文件路径static QString lastUnexpectedFileName;       //上次没有传输完成的源文件名字
static QString lastUnexpectedTargetFileName; //上次没有传输完成的目标文件名字
static quint64 unexpectedFileSize;           //上次文件已传输大小
static quint64 unexpectedFilePos;            //上次文件传输的位置
  1. 在主线程中的析构函数中增加对工作线程的析构,需要注意的是可以通过向工作线程中传入相应的状态,控制线程是否结束,如果强制关闭软件,而线程并不结束
MainWindow::~MainWindow()
{readThread->setStatus(AppConfig::TransferState::Unexpected);writeThread->setStatus(AppConfig::TransferState::Unexpected);threadPool->waitForDone();delete readThread;delete writeThread;delete ui;
}

4 源代码

源代码下载链接

work.h

#ifndef WORK_H
#define WORK_H#include <QObject>
#include <QRunnable>
#include "appconfig.h"
#define DATA_SIZE 1024 * 1024class ReadWork : public QObject,public QRunnable
{Q_OBJECT
public:explicit ReadWork(QObject *parent = nullptr);~ReadWork();void run() override;void getFile(const QString &filePath);void setStatus(const AppConfig::TransferState &status);signals:void sendData(const QByteArray &data);void sendFileInfo(const QString &fileInfo);void msgTips(const QString &msg);void updatePgBar(int num);
private:QString filePath;AppConfig::TransferState status;
};class WriteWork : public QObject,public QRunnable
{Q_OBJECT
public:explicit WriteWork(QObject *parent = nullptr);~WriteWork();void run() override;void getPath(const QString &filePath);void setStatus(const AppConfig::TransferState &status);public slots:void getData(const QByteArray &data);void getFileInfo(const QString &data);
signals:void msgTips(const QString &msg);void updatePgBar(int num);
private:QString filePath;QString fileInfo;QList<QByteArray> arryList;AppConfig::TransferState status;
};#endif // WORK_H

work.cpp

void ReadWork::run()
{//判断文件是否存在QFileInfo fileInfo(filePath);if(!fileInfo.exists()){emit msgTips("文件不存在!");return;}quint64 sourceFileSize = fileInfo.size();quint64 fileSize = (AppConfig::lastUnexpectedFileName.isEmpty())? 0 : AppConfig::unexpectedFileSize;//已经传输的字节quint64 filePos = AppConfig::unexpectedFilePos;//获得文件信息QString fileInfoStr = QString("%1|%2|%3|%4|%5").arg(fileInfo.fileName()).arg(sourceFileSize).arg(fileInfo.absoluteFilePath()).arg(fileInfo.suffix()).arg(fileSize);emit sendFileInfo(fileInfoStr);emit msgTips(fileInfoStr);//打开文件QFile file(filePath);if(!file.open(QIODevice::ReadOnly)){emit msgTips(QString("文件打开失败!%1。").arg(file.errorString()));return;}QByteArray data;//存储发送的数据//移动文件指针file.seek(filePos);//读取文件while(!file.atEnd()){//取消if(status != AppConfig::TransferState::Canceled){//意外关闭if(status == AppConfig::TransferState::Unexpected){//记住文件名称AppConfig::lastUnexpectedFileName = filePath;//记住已经传输的字节AppConfig::unexpectedFileSize = fileSize;//记住文件指针的位置,方便下次传输AppConfig::unexpectedFilePos = file.pos();AppConfig::writeConfig();file.close();return;}//暂停if(status != AppConfig::TransferState::Paused){int readSize = (sourceFileSize-file.pos()<DATA_SIZE)?(sourceFileSize-file.pos()):DATA_SIZE;data = file.read(readSize);fileSize += data.size();int pgBarStep = static_cast<int>(fileSize*100/sourceFileSize);emit updatePgBar(pgBarStep);emit sendData(data);QThread::msleep(100);}else{QThread::msleep(100);}//if(status != AppConfig::TransferState::Paused)}else{file.close();emit updatePgBar(0);emit msgTips("取消文件传输!");return;}}file.close();emit msgTips("读取完毕!");
}写线程
void WriteWork::run()
{//如果文件路径为空,则使用当前应用程序所在路径if(filePath.isEmpty())filePath = QCoreApplication::applicationDirPath();//创建文件QFile file;quint64 sourceFileSize = 0;quint64 currentFileSize = 0;QString fileName="";//获取并解析文件信息if(fileInfo.isEmpty()){emit msgTips("未收到文件信息");return;}QStringList fileInfos = fileInfo.split("|");currentFileSize = fileInfos.last().toUInt();fileName = fileInfos.at(0);sourceFileSize = fileInfos.at(1).toInt();//判断文件是不是重传文件if(currentFileSize > 0){fileName = AppConfig::lastUnexpectedTargetFileName;file.setFileName(fileName);file.rename(fileName.chopped(4));}else{//设置文件相关信息file.setFileName(filePath+"/"+fileName);}emit msgTips("设置文件路径和名称完毕!");//打开文件if(!file.open(QIODevice::ReadWrite)){emit msgTips("文件打开失败:"+file.errorString());return;}emit msgTips("文件打开成功!");//写入数据file.seek(currentFileSize);while(sourceFileSize-currentFileSize>0){//意外关闭-等待旧数据处理完毕才能执行if(status == AppConfig::TransferState::Unexpected && arryList.isEmpty()){file.close();//更改文件名称-在文件后缀中增加.tmpif(file.fileName().count(".tmp")>0)return;file.rename(file.fileName()+".tmp");AppConfig::lastUnexpectedTargetFileName = file.fileName();AppConfig::writeConfig();return;}//取消if(status == AppConfig::TransferState::Canceled){file.close();file.remove();arryList.clear();emit msgTips("文件取消传输");emit updatePgBar(0);if(!AppConfig::lastUnexpectedTargetFileName.isEmpty()){QFile::remove(AppConfig::lastUnexpectedTargetFileName);//重置AppConfig::lastUnexpectedFileName ="";AppConfig::lastUnexpectedTargetFileName ="";AppConfig::unexpectedFileSize = 0;AppConfig::unexpectedFilePos = 0;AppConfig::writeConfig();}return;}//按下暂停键,且数据处理完,才能暂停if(status == AppConfig::TransferState::Paused && arryList.isEmpty()){//暂停QThread::msleep(100);continue;}//防止出现新数据没到,但是旧数据已经处理完if(arryList.isEmpty())continue;QByteArray fileData = arryList.takeFirst();quint64 size = file.write(fileData,fileData.size());currentFileSize += size;int step = static_cast<int>((currentFileSize*100)/sourceFileSize) ;emit updatePgBar(step);QThread::msleep(100);}//whilefile.close();emit msgTips("写入完毕!");if(!AppConfig::lastUnexpectedTargetFileName.isEmpty()){QFile::remove(AppConfig::lastUnexpectedTargetFileName);//重置AppConfig::lastUnexpectedFileName ="";AppConfig::lastUnexpectedTargetFileName ="";AppConfig::unexpectedFileSize = 0;AppConfig::unexpectedFilePos = 0;AppConfig::writeConfig();}
}

相关文章:

QT中级(6)基于QT的文件传输工具(2)

QT中级&#xff08;6&#xff09;基于QT的文件传输工具&#xff08;2&#xff09;本文实现第一步1 新增功能2 运行效果3 实现思路4 源代码实现这个文件传输工具大概需要那几步&#xff1f;实现多线程对文件的读写实现TCP客户端和服务端实现网络传输 书接上回&#xff1a;QT中级…...

【Linux】工具(3)——gcc/g++

咱们继续进阶&#xff0c;接下来进入到Linux工具中gcc和g的学习在本章博客正式开始介绍之前&#xff0c;我们先要弄清楚程序是怎么翻译的&#xff1a;C语言程序环境一、什么是gcc/g&#x1f4cc;gcc是一个c编译器&#xff0c; g是c编译器。我们根据代码的后缀名来判断用哪个编译…...

Android文件选择器

使用方法:在里层的build.grade的dependency里面加入: implementation com.leon:lfilepickerlibrary:1.8.0 引用https://github.com/leonHua/LFilePicker/blob/master/README_CH.md#lfilepicker LFilePicker 说明:如果发现应用名称被修改,可以参考issues#26 查看解决方案,或…...

《MySql学习》 Select 查询语句慢的非性能原因

一.查询被阻塞 A会话执行 查询操作&#xff0c;长时间没有返回信息,此时我们就可以去排查一下是否是被阻塞了 select * from words 被阻塞的原因有很多&#xff0c;首先列举第一种情况 1.等MDL锁 当我们执行DDL语句时&#xff0c;会自动给表加上MDL写锁。当执行DML和DQL时&…...

Vue组件间通信方式超详细(父传子、父传后代、子传父、后代传父、兄弟组件传值)

一、父传子、父传后代 方式一&#xff1a;子通过props来接收 父组件&#xff1a;父组件引入子组件时&#xff0c;通过<child :parentValue "parentValue"></child>子组件传值。 备注&#xff1a;这种方式父传值很方便&#xff0c;但是传递给后代组件不…...

【ES】Elasticsearch-深入理解索引原理

文章目录Elasticsearch-深入理解索引原理读操作更新操作SHARD不变性动态更新索引删除和更新实时索引更新持久化Segment合并近实时搜索&#xff0c;段数据刷新&#xff0c;数据可见性更新和事务日志更新索引并且将改动提交修改Searcher对象默认的更新时间Elasticsearch-深入理解…...

pdf压缩文件大小的方法是什么?word文件怎么批量转换成pdf格式?

大家在存储文件时&#xff0c;通常会遇到一些较大的文件&#xff0c;这时需要对其进行压缩处理。下面介绍一下如何压缩PDF文件大小以及批量转换Word文件为PDF格式。pdf压缩文件大小的方法是什么?1.打开小圆象PDF转换器&#xff0c;选择“PDF压缩”功能。2.在“PDF压缩”界面中…...

论文阅读——FECANet:应用特征增强的上下文感知小样本语义分割网络

代码&#xff1a;NUST-Machine-Intelligence-Laboratory/FECANET (github.com) 文章地址&#xff1a;地址 文章名称&#xff1a;FECANet: Boosting Few-Shot Semantic Segmentation with Feature-Enhanced Context-Aware Network 摘要 Few-shot semantic segmentation 是学习…...

数组模拟常见数据结构

我们来学习一下用数组模拟常见的数据结构&#xff1a;单链表&#xff0c;双链表&#xff0c;栈&#xff0c;队列。用数组模拟这些常见的数据结构&#xff0c;需要我们对这些数据结构有一定的了解哈。单链表请参考&#xff1a;http://t.csdn.cn/SUv8F 用数组模拟实现比STL要快&a…...

ADC0832的AD模数转换原理及编程

✅作者简介&#xff1a;嵌入式领域优质创作者&#xff0c;博客专家 ✨个人主页&#xff1a;咸鱼弟 &#x1f525;系列专栏&#xff1a;单片机设计专栏 &#x1f4c3;推荐一款求职面试、刷题神器&#x1f449;注册免费刷题 目录 一、描述 二、模数转换原理&#xff1a; 三、…...

【工具插件类教学】UnityPackageManager私人定制资源工具包

目录 一.UnityPackageManager的介绍 二.package包命名 三.包的布局 四.生成清单文件 五.制作package内功能 六.为您的软件包撰写文档 1.信息的结构 2.文档格式 七.提交上传云端仓库 1.生成程序集文件 2.上传至云端仓库 八.下载使用package包 1.获取包的云端路径 …...

【软件测试】2023年了还不会接口测试?老鸟总结接口测试面试谁还敢说我不会......

目录&#xff1a;导读前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09;前言 测试面试&#xff0…...

类Vuex轻量级状态管理实现

引用自 摸鱼wiki 1. vuex vuex是一个前端广泛流行的状态管理库&#xff0c;主要由以下几大模块组成&#xff1a; state&#xff1a;状态存储getter&#xff1a;属性访问器mutation&#xff1a;可以理解为一个同步的原子性事务&#xff0c;修改state状态action&#xff1a;触发…...

Java 基本数据类型

Java基本数据类型是Java编程语言中最基本的数据类型&#xff0c;包括整型、浮点型、字符型、布尔型和空类型。本文将详细介绍Java基本数据类型的作用和在实际工作中的用途。 整型&#xff08;int、long、short、byte&#xff09; 整型是Java中最常见的基本数据类型&#xff0…...

全网资料最全Java数据结构与算法-----算法分析

算法分析 研究算法的最终目的就是如何花更少的时间&#xff0c;如何占用更少的内存去完成相同的需求&#xff0c;并且也通过案例演示了不同算法之间时间耗费和空间耗费上的差异&#xff0c;但我们并不能将时间占用和空间占用量化&#xff0c;因此&#xff0c;接下来我们要学习…...

【封装xib补充 Objective-C语言】

一、那么首先,咱们就从这个结果来分析 1.就不给大家一步一步分析了,直接分析我们这里怎么想的, 首先,我们看到这样的一个界面,我们想,这些应用数据是不是来源于一个plist文件吧, 所以说,我们首先要,第一步,要懒加载,把这个plist文件中的数据,加载起来, 那么,因…...

linux + jenkins + svn + maven + node 搭建及部署springboot多模块前后端服务

linux搭建jenkins 基础准备 linux配置jdk、maven&#xff0c;配置系统配置文件 vi /etc/profile配置jdk、maven export JAVA_HOME/usr/java/jdk1.8.0_261-amd64 export CLASSPATH.:$JAVA_HOME/jre/lib/rt.jar:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jarexport MAVEN_H…...

VBA之正则表达式(41)-- 快速标记两个星号之后的字符

实例需求&#xff1a;工作表中的数据保存在A列~G列&#xff0c;现需要识别D列中包含超过两个星号的内容&#xff0c;并将第3个星号及其之后的字符设置为红色字体&#xff0c;如图所示。 示例代码如下。 Sub Demo1()Dim objRegExp As ObjectDim objMatch As ObjectDim strMatch…...

VMware16安装MacOS【详细教程】

安装VMware workstation 双击安装包&#xff0c;然后一直下一步就行了。 进行VMware安装&#xff0c;一直 下一步 在输入产品密钥这一步&#xff0c;如果有查找到可用密钥就填进去&#xff0c;没有就跳过&#xff0c;进入软件后也能输入密钥的。 输入密钥。 最后一步&#xff…...

Netty学习(一):Netty概述

一、原生NIO存在的问题 NIO 的类库和API繁杂&#xff0c;使用麻烦:需要熟练掌握Selector、ServerSocketChannel、SocketChannel、ByteBuffer等。需要具备其他的额外技能:要熟悉Java 多线程编程&#xff0c;因为NIO编程涉及到Reactor 模式&#xff0c;你必须对多线程和网络编程…...

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…...

Ubuntu系统下交叉编译openssl

一、参考资料 OpenSSL&&libcurl库的交叉编译 - hesetone - 博客园 二、准备工作 1. 编译环境 宿主机&#xff1a;Ubuntu 20.04.6 LTSHost&#xff1a;ARM32位交叉编译器&#xff1a;arm-linux-gnueabihf-gcc-11.1.0 2. 设置交叉编译工具链 在交叉编译之前&#x…...

2025年能源电力系统与流体力学国际会议 (EPSFD 2025)

2025年能源电力系统与流体力学国际会议&#xff08;EPSFD 2025&#xff09;将于本年度在美丽的杭州盛大召开。作为全球能源、电力系统以及流体力学领域的顶级盛会&#xff0c;EPSFD 2025旨在为来自世界各地的科学家、工程师和研究人员提供一个展示最新研究成果、分享实践经验及…...

可靠性+灵活性:电力载波技术在楼宇自控中的核心价值

可靠性灵活性&#xff1a;电力载波技术在楼宇自控中的核心价值 在智能楼宇的自动化控制中&#xff0c;电力载波技术&#xff08;PLC&#xff09;凭借其独特的优势&#xff0c;正成为构建高效、稳定、灵活系统的核心解决方案。它利用现有电力线路传输数据&#xff0c;无需额外布…...

在Ubuntu中设置开机自动运行(sudo)指令的指南

在Ubuntu系统中&#xff0c;有时需要在系统启动时自动执行某些命令&#xff0c;特别是需要 sudo权限的指令。为了实现这一功能&#xff0c;可以使用多种方法&#xff0c;包括编写Systemd服务、配置 rc.local文件或使用 cron任务计划。本文将详细介绍这些方法&#xff0c;并提供…...

VTK如何让部分单位不可见

最近遇到一个需求&#xff0c;需要让一个vtkDataSet中的部分单元不可见&#xff0c;查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行&#xff0c;是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示&#xff0c;主要是最后一个参数&#xff0c;透明度…...

全志A40i android7.1 调试信息打印串口由uart0改为uart3

一&#xff0c;概述 1. 目的 将调试信息打印串口由uart0改为uart3。 2. 版本信息 Uboot版本&#xff1a;2014.07&#xff1b; Kernel版本&#xff1a;Linux-3.10&#xff1b; 二&#xff0c;Uboot 1. sys_config.fex改动 使能uart3(TX:PH00 RX:PH01)&#xff0c;并让boo…...

力扣-35.搜索插入位置

题目描述 给定一个排序数组和一个目标值&#xff0c;在数组中找到目标值&#xff0c;并返回其索引。如果目标值不存在于数组中&#xff0c;返回它将会被按顺序插入的位置。 请必须使用时间复杂度为 O(log n) 的算法。 class Solution {public int searchInsert(int[] nums, …...

SiFli 52把Imagie图片,Font字体资源放在指定位置,编译成指定img.bin和font.bin的问题

分区配置 (ptab.json) img 属性介绍&#xff1a; img 属性指定分区存放的 image 名称&#xff0c;指定的 image 名称必须是当前工程生成的 binary 。 如果 binary 有多个文件&#xff0c;则以 proj_name:binary_name 格式指定文件名&#xff0c; proj_name 为工程 名&…...

面向无人机海岸带生态系统监测的语义分割基准数据集

描述&#xff1a;海岸带生态系统的监测是维护生态平衡和可持续发展的重要任务。语义分割技术在遥感影像中的应用为海岸带生态系统的精准监测提供了有效手段。然而&#xff0c;目前该领域仍面临一个挑战&#xff0c;即缺乏公开的专门面向海岸带生态系统的语义分割基准数据集。受…...