Qt之HTTP上傳/下載


簡述

在前面章節中我們講述了關於Qt顯示網絡圖片的內容,比較簡單,因為圖片一般都比較小,下載到本地速度比較快,所以基本不需要什么特殊處理,本節我們主要針對HTTP實現上傳/下載進行詳細的講解與分享,包括:用戶認證,實時獲取下載大小、速度、剩余時間信息等。

首先看一下即將用到的公式:

文件剩余大小 = 文件總大小 - 文件已下載大小 
平均速度 = 文件已下載大小 / 文件已下載大小所用的時間 
瞬時速度 = 每秒下載的文件大小 
剩余時間 = 文件剩余大小 / 瞬時速度

下面以下載為例,來實現一個文件下載管理器。

 

 

效果

這里寫圖片描述

QNetworkAccessManager

DownloadNetworkManager::DownloadNetworkManager(QObject *parent) : QNetworkAccessManager(parent) { // 獲取當前的時間戳,設置下載的臨時文件名稱 QDateTime dateTime = QDateTime::currentDateTime(); QString date = dateTime.toString("yyyy-MM-dd-hh-mm-ss-zzz"); m_strFileName = QString("E:/%1.tmp").arg(date); connect(this, SIGNAL(finished(QNetworkReply *)), this, SLOT(replyFinished(QNetworkReply *))); } DownloadNetworkManager::~DownloadNetworkManager() { // 終止下載 if (m_pReply != NULL) { m_pReply->abort(); m_pReply->deleteLater(); } } // 設置URL及消息頭,開始請求 void DownloadNetworkManager::execute() { m_url = QUrl("http://192.168.*.*/download/2.0.0.zip"); QNetworkRequest request; request.setUrl(m_url); request.setHeader(QNetworkRequest::ContentTypeHeader, "application/zip"); connect(this, SIGNAL(authenticationRequired(QNetworkReply *, QAuthenticator *)), this, SLOT(onAuthenticationRequest(QNetworkReply *, QAuthenticator *))); m_pReply = get(request); connect(m_pReply, SIGNAL(downloadProgress(qint64, qint64)), this, SIGNAL(downloadProgress(qint64, qint64))); connect(m_pReply, SIGNAL(readyRead()), this, SLOT(readyRead())); } void DownloadNetworkManager::replyFinished(QNetworkReply *reply) { // 獲取響應的信息,狀態碼為200表示正常 QVariant statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute); // 無錯誤返回 if (reply->error() == QNetworkReply::NoError) { // 重命名臨時文件 QFileInfo fileInfo(m_strFileName); QFileInfo newFileInfo = fileInfo.absolutePath() + m_url.fileName(); QDir dir; if (dir.exists(fileInfo.absolutePath())) { if (newFileInfo.exists()) newFileInfo.dir().remove(newFileInfo.fileName()); QFile::rename(m_strFileName, newFileInfo.absoluteFilePath()); } } else { QString strError = reply->errorString(); qDebug() << "Error:" << strError; } emit replyFinished(statusCode.toInt()); } // 用戶認證 void DownloadNetworkManager::onAuthenticationRequest(QNetworkReply *reply, QAuthenticator *authenticator) { QByteArray password; password.append("123456"); password = QByteArray::fromBase64(password); QString strPassword(password); authenticator->setUser("wang"); authenticator->setPassword(strPassword); } // 本地寫文件 void DownloadNetworkManager::readyRead() { QFileInfo fileInfo(m_strFileName); QFileInfo newFileInfo = fileInfo.absolutePath() + m_url.fileName(); QString strFileName = newFileInfo.absoluteFilePath(); emit fileName(strFileName); // 寫文件-形式為追加 QFile file(m_strFileName); if (file.open(QIODevice::Append)) file.write(m_pReply->readAll()); file.close(); }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93

使用

調用download()接口開始下載,關聯downloadProgress信號和槽,可以實時獲取下載大小、速度、剩余時間等信息。

// 開始下載 void MainWindow::download() { if (m_pNetworkManager == NULL) { m_pNetworkManager = new DownloadNetworkManager(this); connect(m_pNetworkManager, SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(downloadProgress(qint64, qint64)), Qt::QueuedConnection); connect(m_pNetworkManager, SIGNAL(replyFinished(int)), this, SLOT(replyFinished(int)), Qt::QueuedConnection); connect(m_pNetworkManager, SIGNAL(fileName(QString)), m_pFileInfoLabel, SLOT(setText(QString)), Qt::QueuedConnection); } m_pNetworkManager->execute(); downloadTime.start(); } // 計算下載大小、速度、剩余時間 void MainWindow::downloadProgress(qint64 bytesReceived, qint64 bytesTotal) { // 總時間 int nTime = downloadTime.elapsed(); // 本次下載所用時間 nTime -= m_nTime; // 下載速度 double dBytesSpeed = (bytesReceived * 1000.0) / nTime; double dSpeed = dBytesSpeed; //剩余時間 qint64 leftBytes = (bytesTotal - bytesReceived); double dLeftTime = (leftBytes * 1.0) / dBytesSpeed; m_pSpeedInfoLabel->setText(speed(dSpeed)); m_pLeftTimeInfoLabel->setText(timeFormat(qCeil(dLeftTime))); m_pFileSizeInfoLabel->setText(size(bytesTotal)); m_pDownloadInfoLabel->setText(size(bytesReceived)); m_pProgressBar->setMaximum(bytesTotal); m_pProgressBar->setValue(bytesReceived); // 獲取上一次的時間 m_nTime = nTime; } // 下載完成 void MainWindow::replyFinished(int statusCode) { m_nStatusCode = statusCode; QString strStatus = (statusCode == 200) ? QStringLiteral("下載成功") : QStringLiteral("下載失敗"); m_pStatusLabel->setText(strStatus); }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49

轉換

下面是一些數據的格式轉換,包括:字節轉KB、MB、GB,速度轉KB/S、MB/S、GB/S,秒轉*d *h *m *s格式。

// 字節轉KB、MB、GB
QString size(qint64 bytes)
{
    QString strUnit;
    double dSize = bytes * 1.0; if (dSize <= 0) { dSize = 0.0; } else if (dSize < 1024) { strUnit = "Bytes"; } else if (dSize < 1024 * 1024) { dSize /= 1024; strUnit = "KB"; } else if (dSize < 1024 * 1024 * 1024) { dSize /= (1024 * 1024); strUnit = "MB"; } else { dSize /= (1024 * 1024 * 1024); strUnit = "GB"; } return QString("%1 %2").arg(QString::number(dSize, 'f', 2)).arg(strUnit); } // 速度轉KB/S、MB/S、GB/S QString speed(double speed) { QString strUnit; if (speed <= 0) { speed = 0; strUnit = "Bytes/S"; } else if (speed < 1024) { strUnit = "Bytes/S"; } else if (speed < 1024 * 1024) { speed /= 1024; strUnit = "KB/S"; } else if (speed < 1024 * 1024 * 1024) { speed /= (1024 * 1024); strUnit = "MB/S"; } else { speed /= (1024 * 1024 * 1024); strUnit = "GB/S"; } QString strSpeed = QString::number(speed, 'f', 2); return QString("%1 %2").arg(strSpeed).arg(strUnit); } // 秒轉*d *h *m *s QString timeFormat(int seconds) { QString strValue; QString strSpacing(" "); if (seconds <= 0) { strValue = QString("%1s").arg(0); } else if (seconds < 60) { strValue = QString("%1s").arg(seconds); } else if (seconds < 60 * 60) { int nMinute = seconds / 60; int nSecond = seconds - nMinute * 60; strValue = QString("%1m").arg(nMinute); if (nSecond > 0) strValue += strSpacing + QString("%1s").arg(nSecond); } else if (seconds < 60 * 60 * 24) { int nHour = seconds / (60 * 60); int nMinute = (seconds - nHour * 60 * 60) / 60; int nSecond = seconds - nHour * 60 * 60 - nMinute * 60; strValue = QString("%1h").arg(nHour); if (nMinute > 0) strValue += strSpacing + QString("%1m").arg(nMinute); if (nSecond > 0) strValue += strSpacing + QString("%1s").arg(nSecond); } else { int nDay = seconds / (60 * 60 * 24); int nHour = (seconds - nDay * 60 * 60 * 24) / (60 * 60); int nMinute = (seconds - nDay * 60 * 60 * 24 - nHour * 60 * 60) / 60; int nSecond = seconds - nDay * 60 * 60 * 24 - nHour * 60 * 60 - nMinute * 60; strValue = QString("%1d").arg(nDay); if (nHour > 0) strValue += strSpacing + QString("%1h").arg(nHour); if (nMinute > 0) strValue += strSpacing + QString("%1m").arg(nMinute); if (nSecond > 0) strValue += strSpacing + QString("%1s").arg(nSecond); } return strValue; }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123

總結

一般來說,我們下載文件到本地,需要設置一個臨時文件名,這里我以時間戳為名稱外加.tmp來命名,當然更嚴格的最好再加上隨機數,這樣基本就不會出現重名情況。

下載時,首先判斷本地文件中是否存在與下載文件同名的文件,如果有則刪除,開始下載。當下載完成時,需要對臨時文件重新命名。

以上內容比較詳細,介紹了如何進行用戶認證,如何實時獲取下載大小、速度、剩余時間等信息,后面我們會針對斷點續傳來進行詳細講解,敬請期待!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM