网站建设完提交百度,在家做网站设计,红酒网站建设模板,主题猫-wordpressQT中级#xff08;6#xff09;基于QT的文件传输工具#xff08;2#xff09;本文实现第一步1 新增功能2 运行效果3 实现思路4 源代码实现这个文件传输工具大概需要那几步#xff1f;实现多线程对文件的读写实现TCP客户端和服务端实现网络传输
书接上回#xff1a;QT中级…
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;QListQByteArray 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_castint(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-currentFileSize0){//意外关闭-等待旧数据处理完毕才能执行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_castint((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();}
}