当前位置: 首页 > 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;你必须对多线程和网络编程…...

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…...

【Linux】C语言执行shell指令

在C语言中执行Shell指令 在C语言中&#xff0c;有几种方法可以执行Shell指令&#xff1a; 1. 使用system()函数 这是最简单的方法&#xff0c;包含在stdlib.h头文件中&#xff1a; #include <stdlib.h>int main() {system("ls -l"); // 执行ls -l命令retu…...

Objective-C常用命名规范总结

【OC】常用命名规范总结 文章目录 【OC】常用命名规范总结1.类名&#xff08;Class Name)2.协议名&#xff08;Protocol Name)3.方法名&#xff08;Method Name)4.属性名&#xff08;Property Name&#xff09;5.局部变量/实例变量&#xff08;Local / Instance Variables&…...

Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)

引言&#xff1a;为什么 Eureka 依然是存量系统的核心&#xff1f; 尽管 Nacos 等新注册中心崛起&#xff0c;但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制&#xff0c;是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...

零基础设计模式——行为型模式 - 责任链模式

第四部分&#xff1a;行为型模式 - 责任链模式 (Chain of Responsibility Pattern) 欢迎来到行为型模式的学习&#xff01;行为型模式关注对象之间的职责分配、算法封装和对象间的交互。我们将学习的第一个行为型模式是责任链模式。 核心思想&#xff1a;使多个对象都有机会处…...

pikachu靶场通关笔记22-1 SQL注入05-1-insert注入(报错法)

目录 一、SQL注入 二、insert注入 三、报错型注入 四、updatexml函数 五、源码审计 六、insert渗透实战 1、渗透准备 2、获取数据库名database 3、获取表名table 4、获取列名column 5、获取字段 本系列为通过《pikachu靶场通关笔记》的SQL注入关卡(共10关&#xff0…...

laravel8+vue3.0+element-plus搭建方法

创建 laravel8 项目 composer create-project --prefer-dist laravel/laravel laravel8 8.* 安装 laravel/ui composer require laravel/ui 修改 package.json 文件 "devDependencies": {"vue/compiler-sfc": "^3.0.7","axios": …...

html css js网页制作成品——HTML+CSS榴莲商城网页设计(4页)附源码

目录 一、&#x1f468;‍&#x1f393;网站题目 二、✍️网站描述 三、&#x1f4da;网站介绍 四、&#x1f310;网站效果 五、&#x1fa93; 代码实现 &#x1f9f1;HTML 六、&#x1f947; 如何让学习不再盲目 七、&#x1f381;更多干货 一、&#x1f468;‍&#x1f…...

HDFS分布式存储 zookeeper

hadoop介绍 狭义上hadoop是指apache的一款开源软件 用java语言实现开源框架&#xff0c;允许使用简单的变成模型跨计算机对大型集群进行分布式处理&#xff08;1.海量的数据存储 2.海量数据的计算&#xff09;Hadoop核心组件 hdfs&#xff08;分布式文件存储系统&#xff09;&a…...

基于SpringBoot在线拍卖系统的设计和实现

摘 要 随着社会的发展&#xff0c;社会的各行各业都在利用信息化时代的优势。计算机的优势和普及使得各种信息系统的开发成为必需。 在线拍卖系统&#xff0c;主要的模块包括管理员&#xff1b;首页、个人中心、用户管理、商品类型管理、拍卖商品管理、历史竞拍管理、竞拍订单…...