#include "downloadworker.h" #include #include #include #include #include #include #include DownloadWorker::DownloadWorker(QObject *parent) { } void DownloadWorker::setIdentifier(int identifier) { this->identifier = identifier; } void DownloadWorker::setParamter(const QString &url, QPair range, QFile *file) { this->url = url; this->startPos = range.first; this->endPos = range.second; this->file = file; } qint64 DownloadWorker::getReceivedPos() { return receivedPos; } void DownloadWorker::doWork() { mgr = new QNetworkAccessManager(this); QNetworkRequest request; request.setUrl(url); request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true); request.setRawHeader("Range", QString("bytes=%1-%2").arg(startPos) .arg(endPos).toLocal8Bit()); reply = mgr->get(request); qDebug() << "开始下载数据:" << QString(" %1~%2 -> writePos Start %3") .arg(startPos).arg(endPos).arg(receivedPos); connect(reply, &QNetworkReply::errorOccurred, [this](QNetworkReply::NetworkError error){ if (error != QNetworkReply::NoError) { qDebug() << "出错了:" << reply->errorString(); } }); connect(reply, &QNetworkReply::finished, mgr, &QNetworkAccessManager::deleteLater); connect(reply, &QNetworkReply::finished, reply, &QNetworkReply::deleteLater); connect(reply, &QNetworkReply::readyRead, this, &DownloadWorker::dataReady); connect(reply, &QNetworkReply::finished, this, &DownloadWorker::slotFinish); connect(reply, &QNetworkReply::downloadProgress, this, &DownloadWorker::handleProcess); } void DownloadWorker::doStop() { reply->deleteLater(); reply = nullptr; mgr->deleteLater(); mgr = nullptr; } void DownloadWorker::dataReady() { qDebug() << QString("测试是否执行: %1 %2").arg(startPos).arg(receivedPos); QByteArray data = reply->readAll(); file->seek(startPos + receivedPos); file->write(data); receivedPos += data.size(); } void DownloadWorker::slotFinish() { file->flush(); qDebug() << "数据块下载完毕:" << QString(" %1~%2 -> writePos Start %3") .arg(startPos).arg(endPos).arg(receivedPos); emit workFinished(); } void DownloadWorker::handleProcess(qint64, qint64) { emit this->downloadProcess(); } DownloadController::DownloadController(QObject *parent) { this->threadNum = 4; } void DownloadController::setFilename(QString filename) { this->filename = filename; } void DownloadController::setThreadNum(int threadNum) { this->threadNum = threadNum; } /** * @brief 开始下载 */ void DownloadController::startDownload(const QString &url, qint64 fileSize) { finish = 0; // 下载任务等分,计算每个线程的下载数据 this->fileSize = fileSize; qint64 segmentSize = fileSize / threadNum; ranges.resize(threadNum); QVector receivedBytes; receivedBytes.resize(threadNum); for (int i = 0; i < threadNum; i++) { ranges[i].first = i * segmentSize; ranges[i].second = i * segmentSize + segmentSize - 1; receivedBytes[i] = 0; } ranges[threadNum-1].second = fileSize; // 余数部分加入最后一个 // 打开文件 file = new QFile; file->setFileName(filename); if (file->exists()) file->remove(); if (!file->open(QIODevice::WriteOnly)) { delete file; file = nullptr; emit errorOccur(file->errorString()); return; } file->resize(fileSize); // 创建下载线程 for(int i = 0; i < ranges.size(); i++) { qDebug() << QString("第%1个下载请求:%2-%3").arg(i).arg(ranges.at(i).first).arg(ranges.at(i).second); auto worker = new DownloadWorker(this); auto range = ranges.at(i); worker->setIdentifier(i); worker->setParamter(url, range, file); workers.append(worker); connect(worker, &DownloadWorker::downloadProcess, this, &DownloadController::handleProcess); connect(worker, &DownloadWorker::workFinished, this, &DownloadController::chunkDownloadFinish); worker->doWork(); } } /** * @brief 停止下载 */ void DownloadController::stopDownload() { for(int i = 0; i < workers.size(); i++) { workers.at(i)->doStop(); } file->flush(); file->close(); delete file; file = nullptr; } void DownloadController::handleProcess() { qint64 bytesReceived = 0; for(int i = 0; i < workers.size(); i++) { bytesReceived += workers.at(i)->getReceivedPos(); } qDebug() << QString("下载进度 %1-%2").arg(bytesReceived).arg(fileSize); emit downloadProcess(bytesReceived, fileSize); } void DownloadController::chunkDownloadFinish() { finish++; if (finish == threadNum) { emit downloadFinished(); } }