QT中级(6)基于QT的文件传输工具(2)
QT中级(6)基于QT的文件传输工具(2)
- 本文实现第一步
- 1 新增功能
- 2 运行效果
- 3 实现思路
- 4 源代码
实现这个文件传输工具大概需要那几步?
- 实现多线程对文件的读写
- 实现TCP客户端和服务端
- 实现网络传输
书接上回:QT中级(5)多线程读取一个文件,并在另一个文件夹中合成这个文件(1)
本文实现第一步
1 新增功能
- 增加线程暂停和取消功能
- 增加意外关闭软件,再次打开可以重新续传
- 增加对线程的析构
2 运行效果

3 实现思路
- 通过创建标识符,控制线程的开始、暂停、取消(结束)
//线程工作状态
enum class TransferState {None,Running,Paused,Canceled,Unexpected
};
- 增加配置文件,记住软件运行的状态和一些文件相关信息
static QString configFilePath; //配置文件路径
static QString sourceFilePath; //源文件路径
static QString targetFilePath; //目标文件路径static QString lastUnexpectedFileName; //上次没有传输完成的源文件名字
static QString lastUnexpectedTargetFileName; //上次没有传输完成的目标文件名字
static quint64 unexpectedFileSize; //上次文件已传输大小
static quint64 unexpectedFilePos; //上次文件传输的位置
- 在主线程中的析构函数中增加对工作线程的析构,需要注意的是可以通过向工作线程中传入相应的状态,控制线程是否结束,如果强制关闭软件,而线程并不结束
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中级(6)基于QT的文件传输工具(2)本文实现第一步1 新增功能2 运行效果3 实现思路4 源代码实现这个文件传输工具大概需要那几步?实现多线程对文件的读写实现TCP客户端和服务端实现网络传输 书接上回:QT中级…...
【Linux】工具(3)——gcc/g++
咱们继续进阶,接下来进入到Linux工具中gcc和g的学习在本章博客正式开始介绍之前,我们先要弄清楚程序是怎么翻译的:C语言程序环境一、什么是gcc/g📌gcc是一个c编译器, 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会话执行 查询操作,长时间没有返回信息,此时我们就可以去排查一下是否是被阻塞了 select * from words 被阻塞的原因有很多,首先列举第一种情况 1.等MDL锁 当我们执行DDL语句时,会自动给表加上MDL写锁。当执行DML和DQL时&…...
Vue组件间通信方式超详细(父传子、父传后代、子传父、后代传父、兄弟组件传值)
一、父传子、父传后代 方式一:子通过props来接收 父组件:父组件引入子组件时,通过<child :parentValue "parentValue"></child>子组件传值。 备注:这种方式父传值很方便,但是传递给后代组件不…...
【ES】Elasticsearch-深入理解索引原理
文章目录Elasticsearch-深入理解索引原理读操作更新操作SHARD不变性动态更新索引删除和更新实时索引更新持久化Segment合并近实时搜索,段数据刷新,数据可见性更新和事务日志更新索引并且将改动提交修改Searcher对象默认的更新时间Elasticsearch-深入理解…...
pdf压缩文件大小的方法是什么?word文件怎么批量转换成pdf格式?
大家在存储文件时,通常会遇到一些较大的文件,这时需要对其进行压缩处理。下面介绍一下如何压缩PDF文件大小以及批量转换Word文件为PDF格式。pdf压缩文件大小的方法是什么?1.打开小圆象PDF转换器,选择“PDF压缩”功能。2.在“PDF压缩”界面中…...
论文阅读——FECANet:应用特征增强的上下文感知小样本语义分割网络
代码:NUST-Machine-Intelligence-Laboratory/FECANET (github.com) 文章地址:地址 文章名称:FECANet: Boosting Few-Shot Semantic Segmentation with Feature-Enhanced Context-Aware Network 摘要 Few-shot semantic segmentation 是学习…...
数组模拟常见数据结构
我们来学习一下用数组模拟常见的数据结构:单链表,双链表,栈,队列。用数组模拟这些常见的数据结构,需要我们对这些数据结构有一定的了解哈。单链表请参考:http://t.csdn.cn/SUv8F 用数组模拟实现比STL要快&a…...
ADC0832的AD模数转换原理及编程
✅作者简介:嵌入式领域优质创作者,博客专家 ✨个人主页:咸鱼弟 🔥系列专栏:单片机设计专栏 📃推荐一款求职面试、刷题神器👉注册免费刷题 目录 一、描述 二、模数转换原理: 三、…...
【工具插件类教学】UnityPackageManager私人定制资源工具包
目录 一.UnityPackageManager的介绍 二.package包命名 三.包的布局 四.生成清单文件 五.制作package内功能 六.为您的软件包撰写文档 1.信息的结构 2.文档格式 七.提交上传云端仓库 1.生成程序集文件 2.上传至云端仓库 八.下载使用package包 1.获取包的云端路径 …...
【软件测试】2023年了还不会接口测试?老鸟总结接口测试面试谁还敢说我不会......
目录:导读前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结(尾部小惊喜)前言 测试面试࿰…...
类Vuex轻量级状态管理实现
引用自 摸鱼wiki 1. vuex vuex是一个前端广泛流行的状态管理库,主要由以下几大模块组成: state:状态存储getter:属性访问器mutation:可以理解为一个同步的原子性事务,修改state状态action:触发…...
Java 基本数据类型
Java基本数据类型是Java编程语言中最基本的数据类型,包括整型、浮点型、字符型、布尔型和空类型。本文将详细介绍Java基本数据类型的作用和在实际工作中的用途。 整型(int、long、short、byte) 整型是Java中最常见的基本数据类型࿰…...
全网资料最全Java数据结构与算法-----算法分析
算法分析 研究算法的最终目的就是如何花更少的时间,如何占用更少的内存去完成相同的需求,并且也通过案例演示了不同算法之间时间耗费和空间耗费上的差异,但我们并不能将时间占用和空间占用量化,因此,接下来我们要学习…...
【封装xib补充 Objective-C语言】
一、那么首先,咱们就从这个结果来分析 1.就不给大家一步一步分析了,直接分析我们这里怎么想的, 首先,我们看到这样的一个界面,我们想,这些应用数据是不是来源于一个plist文件吧, 所以说,我们首先要,第一步,要懒加载,把这个plist文件中的数据,加载起来, 那么,因…...
linux + jenkins + svn + maven + node 搭建及部署springboot多模块前后端服务
linux搭建jenkins 基础准备 linux配置jdk、maven,配置系统配置文件 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)-- 快速标记两个星号之后的字符
实例需求:工作表中的数据保存在A列~G列,现需要识别D列中包含超过两个星号的内容,并将第3个星号及其之后的字符设置为红色字体,如图所示。 示例代码如下。 Sub Demo1()Dim objRegExp As ObjectDim objMatch As ObjectDim strMatch…...
VMware16安装MacOS【详细教程】
安装VMware workstation 双击安装包,然后一直下一步就行了。 进行VMware安装,一直 下一步 在输入产品密钥这一步,如果有查找到可用密钥就填进去,没有就跳过,进入软件后也能输入密钥的。 输入密钥。 最后一步ÿ…...
Netty学习(一):Netty概述
一、原生NIO存在的问题 NIO 的类库和API繁杂,使用麻烦:需要熟练掌握Selector、ServerSocketChannel、SocketChannel、ByteBuffer等。需要具备其他的额外技能:要熟悉Java 多线程编程,因为NIO编程涉及到Reactor 模式,你必须对多线程和网络编程…...
Android Wi-Fi 连接失败日志分析
1. Android wifi 关键日志总结 (1) Wi-Fi 断开 (CTRL-EVENT-DISCONNECTED reason3) 日志相关部分: 06-05 10:48:40.987 943 943 I wpa_supplicant: wlan0: CTRL-EVENT-DISCONNECTED bssid44:9b:c1:57:a8:90 reason3 locally_generated1解析: CTR…...
椭圆曲线密码学(ECC)
一、ECC算法概述 椭圆曲线密码学(Elliptic Curve Cryptography)是基于椭圆曲线数学理论的公钥密码系统,由Neal Koblitz和Victor Miller在1985年独立提出。相比RSA,ECC在相同安全强度下密钥更短(256位ECC ≈ 3072位RSA…...
NLP学习路线图(二十三):长短期记忆网络(LSTM)
在自然语言处理(NLP)领域,我们时刻面临着处理序列数据的核心挑战。无论是理解句子的结构、分析文本的情感,还是实现语言的翻译,都需要模型能够捕捉词语之间依时序产生的复杂依赖关系。传统的神经网络结构在处理这种序列依赖时显得力不从心,而循环神经网络(RNN) 曾被视为…...
深入解析C++中的extern关键字:跨文件共享变量与函数的终极指南
🚀 C extern 关键字深度解析:跨文件编程的终极指南 📅 更新时间:2025年6月5日 🏷️ 标签:C | extern关键字 | 多文件编程 | 链接与声明 | 现代C 文章目录 前言🔥一、extern 是什么?&…...
算法:模拟
1.替换所有的问号 1576. 替换所有的问号 - 力扣(LeetCode) 遍历字符串:通过外层循环逐一检查每个字符。遇到 ? 时处理: 内层循环遍历小写字母(a 到 z)。对每个字母检查是否满足: 与…...
莫兰迪高级灰总结计划简约商务通用PPT模版
莫兰迪高级灰总结计划简约商务通用PPT模版,莫兰迪调色板清新简约工作汇报PPT模版,莫兰迪时尚风极简设计PPT模版,大学生毕业论文答辩PPT模版,莫兰迪配色总结计划简约商务通用PPT模版,莫兰迪商务汇报PPT模版,…...
第7篇:中间件全链路监控与 SQL 性能分析实践
7.1 章节导读 在构建数据库中间件的过程中,可观测性 和 性能分析 是保障系统稳定性与可维护性的核心能力。 特别是在复杂分布式场景中,必须做到: 🔍 追踪每一条 SQL 的生命周期(从入口到数据库执行)&#…...
MySQL 索引底层结构揭秘:B-Tree 与 B+Tree 的区别与应用
文章目录 一、背景知识:什么是 B-Tree 和 BTree? B-Tree(平衡多路查找树) BTree(B-Tree 的变种) 二、结构对比:一张图看懂 三、为什么 MySQL InnoDB 选择 BTree? 1. 范围查询更快 2…...
OD 算法题 B卷【正整数到Excel编号之间的转换】
文章目录 正整数到Excel编号之间的转换 正整数到Excel编号之间的转换 excel的列编号是这样的:a b c … z aa ab ac… az ba bb bc…yz za zb zc …zz aaa aab aac…; 分别代表以下的编号1 2 3 … 26 27 28 29… 52 53 54 55… 676 677 678 679 … 702 703 704 705;…...
tauri项目,如何在rust端读取电脑环境变量
如果想在前端通过调用来获取环境变量的值,可以通过标准的依赖: std::env::var(name).ok() 想在前端通过调用来获取,可以写一个command函数: #[tauri::command] pub fn get_env_var(name: String) -> Result<String, Stri…...
