photodownloader.h文件
#ifndef PHOTODOWNLOADER_H #define PHOTODOWNLOADER_H #include <QObject> #include <QTimer> #include <QThread> #include <QList> #include <QUrl> #include <QDir> #include <QMutex> #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<int,WithinTablePushButton *> viewImgBtnMap; //违章页面的查看按钮 private: static PhotoDownloader *self; bool isTaskActive; quint16 board_id; QList<FtpDownloader *>downloaderList; int maxDownloaderNum; //下载器最大数量 #endif // PHOTODOWNLOADER_Hphotodownloader.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;downloaderId<maxDownloaderNum;downloaderId++){ downloaderList.append(new FtpDownloader(downloaderId)); connect(downloaderList.at(downloaderId),&FtpDownloader::downloadFinish,this,&PhotoDownloader::prepareDownload); downloaderList[downloaderId]->setProperty("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;downloaderId<qMin(imgNum,maxDownloaderNum);downloaderId++){ prepareDownload(downloaderId); downloaderList[downloaderId]->setProperty("isBusy",true); else{ //如果有未开启的下载器则开启 for(int i=0;i<maxDownloaderNum;i++){ if(!downloaderList[i]->property("isBusy").toBool()){ prepareDownload(i); downloaderList[i]->setProperty("isBusy",true); qDebug()<<"新开启"<<i<<"号下载器"; break; void PhotoDownloader::prepareDownload(int downloaderId) int violationId; QString imgName; if( MyDatabase::Instance()->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()<<QString("下载器%1 发现 无未下载图片").arg(downloaderId); downloaderList[downloaderId]->setProperty("isBusy",false); for(int i=0;i<maxDownloaderNum;i++){ if(downloaderList[i]->property("isBusy").toBool()) return; qDebug()<<"所有下载器均空闲"; isTaskActive = false;ftpdownloader.h文件
#ifndef FTPDOWNLOADER_H #define FTPDOWNLOADER_H #include <QObject> #include <QDir> #include <QUrl> #include "mydatabase.h" #include <QNetworkAccessManager> #include <QNetworkReply> #include <QTimer> #include <QDebug> #include <QMetaEnum> #include <QThread> 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_Hftpdownloader.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<void(QNetworkReply::*)(QNetworkReply::NetworkError)>(&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<QNetworkReply::NetworkError>(); //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()<<"下载器:"<<this->downloaderId<<" 总大小:"<<bytesTotal/1024<<"kb 已下载:"<<bytesReceived/1024<<"kb"; if( PhotoDownloader::Instance()->viewImgBtnMap.contains(violationId) ){