簡述
在前面章節中我們講述了關於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來命名,當然更嚴格的最好再加上隨機數,這樣基本就不會出現重名情況。
下載時,首先判斷本地文件中是否存在與下載文件同名的文件,如果有則刪除,開始下載。當下載完成時,需要對臨時文件重新命名。
以上內容比較詳細,介紹了如何進行用戶認證,如何實時獲取下載大小、速度、剩余時間等信息,后面我們會針對斷點續傳來進行詳細講解,敬請期待!