代码如下
photodownloader.h文件
#ifndef PHOTODOWNLOADER_H
#define PHOTODOWNLOADER_H
#include
#include
#include
#include
#include
#include
#include
#include "communicate.h"
#include "mydatabase.h"
#include "ftpdownloader.h"
#include "withintablepushbutton.h"
/**
violation表imgexist字段含义:0-未下载 1-已下载 2-下载失败 3-正在下载
*/
class PhotoDownloader : public QObject
{
Q_OBJECT
public:
//单例模式
static PhotoDownloader *Instance();
//构造函数
explicit PhotoDownloader(QObject *parent = Q_NULLPTR);
void initTask();
private:
//初始化imgexist字段(如果存在3则置为0)
void initImgExistField();
void prepareDownload(int downloaderId);
public:
QMap viewImgBtnMap; //违章页面的查看按钮
private:
static PhotoDownloader *self;
bool isTaskActive;
quint16 board_id;
QListdownloaderList;
int maxDownloaderNum; //下载器最大数量
};
#endif // PHOTODOWNLOADER_H
photodownloader.cpp文件
#pragma execution_character_set("utf-8")
#include "photodownloader.h"
//单例模式
PhotoDownloader *PhotoDownloader::self = nullptr;
PhotoDownloader *PhotoDownloader::Instance()
{
if (!self) {
QMutex mutex;
QMutexLocker locker(&mutex);
if (!self) {
self = new PhotoDownloader;
}
}
return self;
}
//构造函数
PhotoDownloader::PhotoDownloader(QObject *parent):QObject(parent),isTaskActive(false)
,maxDownloaderNum(3)
{
initImgExistField();
//创建下载器
for(int downloaderId=0;downloaderIdsetProperty("isBusy",false);
}
//设备连接时自动调用initTask
connect(Communicate::Instance(),&Communicate::hasConnected,[=]{
this->board_id = Communicate::Instance()->getBoardId();
initTask();
});
}
//初始化imgexist字段(如果存在3则置为0)
void PhotoDownloader::initImgExistField()
{
MyDatabase::Instance()->restoreViolationImgexistField();
}
void PhotoDownloader::initTask()
{
if(!isTaskActive){
isTaskActive = true;
//获取未下载的图片数
int imgNum = MyDatabase::Instance()->getUndownloadImgNum(this->board_id);
if(imgNum<=0){
isTaskActive = false;
return;
}
//准备下载
for(int downloaderId=0;downloaderIdsetProperty("isBusy",true);
}
}
else{
//如果有未开启的下载器则开启
for(int i=0;iproperty("isBusy").toBool()){
prepareDownload(i);
downloaderList[i]->setProperty("isBusy",true);
qDebug()<<"新开启"<getEarliestImgName(this->board_id,violationId,imgName) ){
QString url = "ftp://speedtest.tele2.net/" + imgName;
QString dir = QDir::currentPath() + "/violationPhoto";
MyDatabase::Instance()->updateImgexistById(violationId,3);//将imgexist改为3(正在下载)
downloaderList[downloaderId]->startDownload(violationId,url,dir);
}
else{
qDebug()<setProperty("isBusy",false);
for(int i=0;iproperty("isBusy").toBool()) return;
}
qDebug()<<"所有下载器均空闲";
isTaskActive = false;
}
}
ftpdownloader.h文件
#ifndef FTPDOWNLOADER_H
#define FTPDOWNLOADER_H
#include
#include
#include
#include "mydatabase.h"
#include
#include
#include
#include
#include
#include
class FtpDownloader : public QObject
{
Q_OBJECT
public:
explicit FtpDownloader(int downloaderId,QObject *parent = Q_NULLPTR);
void startDownload(int violationId, QString url, QString dir);
private:
//检查Url正确性
bool checkUrl();
//检查保存目录正确性
bool checkSaveDir();
//创建下载文件
bool createDownloadFile();
signals:
void downloadFinish(int downloaderId);//下载结束信号
private slots:
void timeOut();
void slotReadyRead();
void readReplyError(QNetworkReply::NetworkError error);
void downloadFinishReply(QNetworkReply* reply);
void downloadProgress(qint64 bytesReceived, qint64 bytesTotal);
private:
int downloaderId;//当前下载器的编号
int violationId;
QUrl url;
QDir dir;
QFile *file;
QTimer *timer;
qint64 fileDownloadSize;
qint64 lastDownloadSize;
QNetworkReply *downloadReply;
QNetworkAccessManager *downloadManager;
};
#endif // FTPDOWNLOADER_H
ftpdownloader.cpp文件
#pragma execution_character_set("utf-8")
#include "ftpdownloader.h"
#include "photodownloader.h"
FtpDownloader::FtpDownloader(int downloaderId,QObject *parent):QObject(parent)
{
this->downloaderId = downloaderId;
downloadManager = new QNetworkAccessManager(this);
connect(downloadManager,&QNetworkAccessManager::finished,this,&FtpDownloader::downloadFinishReply);
timer = new QTimer(this);
connect(timer,&QTimer::timeout,this,&FtpDownloader::timeOut);
}
//检查Url正确性
bool FtpDownloader::checkUrl()
{
if(!url.isValid()) return false;
if(url.scheme() != "ftp") return false;
if(url.path().isEmpty() || url.path()=="/") return false;
return true;
}
//检查保存目录正确性
bool FtpDownloader::checkSaveDir()
{
//如果目录不存在就创建目录
if(!dir.exists())
{
if(!dir.mkpath(dir.absolutePath())) return false;
}
return true;
}
//创建下载文件
bool FtpDownloader::createDownloadFile()
{
//从url中截取出文件名
QString localFileName = QFileInfo(url.path()).fileName();
localFileName = QString("%1-下载器%2-%3").arg(this->violationId).arg(this->downloaderId).arg(localFileName);//(临时这样命名文件)
file = new QFile();
file->setFileName(dir.absoluteFilePath(localFileName));
if(!file->open(QIODevice::WriteOnly)) return false;
return true;
}
void FtpDownloader::startDownload(int violationId, QString url, QString dir)
{
this->violationId = violationId;
this->url = QUrl(url);
this->dir = QDir(dir);
if( !checkUrl() || !checkSaveDir() || !createDownloadFile() ){
MyDatabase::Instance()->updateImgexistById(violationId,2);//将imgexist改为2(下载失败)
if( PhotoDownloader::Instance()->viewImgBtnMap.contains(violationId) ){ //将按钮文字改为“不存在”
PhotoDownloader::Instance()->viewImgBtnMap.value(violationId)->setText("不存在");
}
emit downloadFinish(this->downloaderId);
return;
}
fileDownloadSize = 0;
lastDownloadSize = 0;
downloadReply = downloadManager->get(QNetworkRequest(url));
connect(downloadReply,&QNetworkReply::readyRead,this,&FtpDownloader::slotReadyRead);
connect(downloadReply,&QNetworkReply::downloadProgress,this,&FtpDownloader::downloadProgress);
connect(downloadReply,static_cast(&QNetworkReply::error),this,&FtpDownloader::readReplyError);
if(!timer->isActive()) timer->start(30 * 1000);//启动超时检查定时器,每30秒查询下载情况
}
void FtpDownloader::timeOut()
{
if(lastDownloadSize != fileDownloadSize){
lastDownloadSize = fileDownloadSize;//更新lastDownloadSize
}
else{
//如果30秒之前下载了的文件大小等于下载下载了的文件大小,就主动发出超时error信号
emit downloadReply->error(QNetworkReply::TimeoutError);
}
}
void FtpDownloader::slotReadyRead()
{
file->write(downloadReply->readAll());
fileDownloadSize = file->size();//更新下载字节数
}
void FtpDownloader::readReplyError(QNetworkReply::NetworkError error)
{
//打印错误信息
QMetaEnum metaEnum = QMetaEnum::fromType();
//PS:字符串转换为枚举值
//Qt::Alignment alignment = (Qt::Alignment)metaEnum.keyToValue("Qt::AlignLeft");
//alignment = (Qt::Alignment)metaEnum.keysToValue("Qt::AlignLeft | Qt::AlignVCenter");
//枚举值转换为字符串
const char *errStr = metaEnum.valueToKey(error);
qDebug()<<"文件下载error: " + QString(errStr);
file->close();
file->deleteLater();
file = Q_NULLPTR;
downloadReply->deleteLater();
downloadReply = Q_NULLPTR;
startDownload(violationId,url.toString(),dir.absolutePath()); //重新尝试下载文件
}
void FtpDownloader::downloadFinishReply(QNetworkReply *reply)
{
if(timer->isActive()) timer->stop(); //停止超时计时器
file->waitForBytesWritten(5 * 1000); //等待文件写入结束(5秒钟)
if(file->size()==0){
// MyDatabase::Instance()->updateImgexistById(violationId,2);
}
else{
MyDatabase::Instance()->updateImgexistById(violationId,1);
}
file->close();
file->deleteLater();
file = Q_NULLPTR;
reply->deleteLater();
reply = Q_NULLPTR;
emit downloadFinish(this->downloaderId);
}
void FtpDownloader::downloadProgress(qint64 bytesReceived, qint64 bytesTotal)
{
if(bytesTotal!=0)
{
qDebug()<<"下载器:"<downloaderId<<" 总大小:"<viewImgBtnMap.contains(violationId) ){
PhotoDownloader::Instance()->viewImgBtnMap.value(violationId)->setProgress(bytesReceived,bytesTotal);
}
}
}