1. 程式人生 > >QtDownloadTool——簡單的HTTP資源下載工具

QtDownloadTool——簡單的HTTP資源下載工具

閒話

之前想著迅雷9那廣告滿天的介面,簡直被噁心到了,就想著自己寫個下載工具,結果花幾個小時寫好(copy好別人的程式碼),發現還是TM迅雷下載著舒服,畢竟人家那這麼多年的P2P技術不是擺設,自己也只是寫著玩玩兒,學習學習而已。程式執行圖如下:
這裡寫圖片描述

資源獲取

要下載檔案之前,當然要獲取到資原始檔,才可以開始下載,Qt實現了一個簡單的資源獲取方法:

/* 通過url獲取檔名 */
QString Network::getFileInfo(QString task
) { QUrl url = QUrl::fromEncoded(task.toLocal8Bit()); QString path = url.path(); QString fileName = QFileInfo(path).fileName(); return fileName; }

在我們的面前就是傳個url的path到QFileInfo類中,然後就可以返回資源名,很簡單,當然只能獲取簡單的資原始檔,要是像什麼度娘上的圖片或者度盤的連結,是識別不出來的。之前也看過別人的部落格說可以先發http請求獲取,不過自己沒試過,也不知道是否可行。

開始下載

既然是一個HTTP資源下載工具,當然需要設計到HTTP請求,這裡的請求很簡單,其實也就是設定一下HTTP請求頭而已:

QNetworkRequest request(url);

request.setRawHeader("User-Agent", "MyOwnBrowser 1.0");
request.setRawHeader("Range", QString("bytes=%1-").arg(currentFileSize).toLatin1());

第一個請求頭,產生請求的瀏覽器型別;
第二個請求頭,接收檔案的位置和範圍。這個請求是最關鍵的,用來實現斷點續傳。

設定好請求頭後,只需要連線幾個接收的槽函式,就可以開始接收檔案了:

reply = manager.get(request);

connect(reply, SIGNAL(readyRead()), this, SLOT(readyToRead()));
connect(reply, SIGNAL(finished()),  this, SLOT(downloadFinished()));
connect(reply, SIGNAL(downloadProgress(qint64,qint64)),
        this, SLOT(downloadProgress(qint64,qint64)));
connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),
        this, SLOT(downloadError(QNetworkReply::NetworkError)));

這幾個槽的意思就很清楚了:
第一個,資料準備好,等著我們去讀了;
第二個,檔案接收完成;
第三個,接收的進度;
第四個,接收過程中發生的錯誤。

讀函式,只需要往檔案裡寫就對了:

void Network::readyToRead()
{
    /* write data to file */
    file.write(reply->readAll());
}

錯誤處理,這裡我就只把錯誤打印出來,把下載停了就完事兒了,沒做過多處理:

void Network::downloadError(QNetworkReply::NetworkError code)
{
    qDebug() << "Failed: " << code;

    stopTask(currentTask);
}

接收完成,向介面傳送訊息,同時把任務從下載列表中刪除掉,如果任務佇列不為空就開始下一個任務:

void Network::downloadFinished()
{
    file.close();

    timeElapsed = 0;

    isDownloading = false;

    downloadList.removeOne(currentTask);

    if (reply->error()) {
        qDebug() << "Failed: " << reply->errorString();
        return ;
    }

    reply->deleteLater();

    emit taskFinished(currentTask);

    if (!downloadList.isEmpty()) {
        QString taskNext = downloadList.first();
        startDownload(taskNext, downloadPath);
    }
}

從上面可以看出,這裡也列印了錯誤資訊,因為當發生錯誤,傳輸中斷後,也會接收到finished()訊號。

下載進度,在這可以獲取下載到的檔案大小,然後自己也可以實現速度計算:

void Network::downloadProgress(qint64 bytesReceived, qint64 byteTotal)
{
    double speed = (bytesReceived * 1000.0) / (downloadTime.elapsed() + timeElapsed);
    timeLast  = downloadTime.elapsed();

//    qDebug() << "Time elapse:" << downloadTime.elapsed() + timeElapsed;

    double percent = (bytesReceived + currentFileSize) * 100.0 / (byteTotal + currentFileSize);
    if (percent >= 100.0) {
        downloadFinished();
        return ;
    }

    emit process(currentTask, byteTotal + currentFileSize, percent, speed);
}

需要注意的是,如果是斷點續傳,這裡獲取到的byteTotal是還未接收的資料大小,所以需要把之前下載大小儲存起來,當然也可以通過讀已寫檔案大小來獲取。

至於介面什麼的,就不說了,不得不承認自己沒有一點藝術細胞,程式碼下載地址:
https://github.com/DragonPang/QTDownloadTool