QT assistant 中有关QHttp的说明,建议我们使用 QNetworkAccessManager 和 QNetworkReply 而非QHttp,因为前者的API更多,并且提供了更丰富的错误处理。
下面是利用QNetworkAccessManager 和 QNetworkReply 实现的一个http下载类,由于QNetworkAccessManager里面没有提供网络连接中断和超时的错误处理,所以中间我用了QTimer来进行这个容错处理。
下面代码里,如果发现在下载过程中网络中断,我将重新下载 所有文件 ,并且永不停悉。(maybe it's not used for u, u can comment that).
Head file:
#ifndef IHTTPDOWNLOADS_H #define IHTTPDOWNLOADS_H
#include <QObject> #include <QNetworkAccessManager> #include <QUrl> #include <QFile> #include <QNetworkReply> #include <QTimer> #include <QProgressBar>
class iHttpDownloadS : public QObject { Q_OBJECT public: explicit iHttpDownloadS(QObject *parent = 0, QProgressBar *_progressBar = 0); ~iHttpDownloadS(); bool getFileFromURL(const QUrl &url, const QString &filePath); /* get file from url which we need to download, and restore to filePath */
const QString &getLastErrorMessage(); /* if error occurs, use this to get the error message */ void setErrorMessage(const QString &msg); /* set _errMsg */
signals:
public slots: void replyFinished(QNetworkReply*); /* download finished */ void replayDownloadProgress(qint64, qint64); /* downloading... */ void slotError(QNetworkReply::NetworkError); /* handle error */ void slotReadyRead();/* ready read */ void handleTimeOut(); /* handle time out */
private: QNetworkAccessManager *_downloadManager; QNetworkReply *_reply; QString _errMsg; QFile _file; QProgressBar *_progressBar; QTimer *_timeOut; QString _filePath; QUrl _url; };
#endif // IHTTPDOWNLOADS_H
|
Implementation file:
#include "ihttpdownloads.h" #include <QDebug>
iHttpDownloadS::iHttpDownloadS(QObject *parent, QProgressBar *bar) : QObject(parent), _progressBar(bar) { _downloadManager = new QNetworkAccessManager(this); _timeOut = new QTimer(this); connect(_downloadManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyFinished(QNetworkReply*))); connect(_timeOut, SIGNAL(timeout()), this, SLOT(handleTimeOut())); } iHttpDownloadS::~iHttpDownloadS() { _reply->deleteLater(); _downloadManager->deleteLater(); }
bool iHttpDownloadS::getFileFromURL(const QUrl &url, const QString &filePath) /* get file from url which we need to download, and restore to filePath */ { /* confirm the url is valid or not */ if (!url.isValid()) { setErrorMessage(QString("Error:URL has specify a invalid name.")); return false; }
if (url.scheme() != "http") { setErrorMessage(QString("Error:URL must start with 'http:'")); return false; }
if (url.path().isEmpty()) { setErrorMessage(QString("Error:URL's path is empty.")); return false; }
if (filePath.isEmpty()) { setErrorMessage(QString("Error:invalid filePath.")); return false; }
_file.setFileName(filePath); if (!_file.open(QIODevice::WriteOnly)) { setErrorMessage(QString("Error:Cannot open file.")); return false; } _url = url; _filePath = filePath;
_reply = _downloadManager->get(QNetworkRequest(url)); connect(_reply, SIGNAL(readyRead()), this, SLOT(slotReadyRead())); connect(_reply, SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(replayDownloadProgress(qint64, qint64))); connect(_reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(slotError(QNetworkReply::NetworkError)));
return true; }
const QString &iHttpDownloadS::getLastErrorMessage() { return _errMsg; } void iHttpDownloadS::setErrorMessage(const QString &msg) { qDebug()<<msg; _errMsg = msg; }
/* slots */ void iHttpDownloadS::handleTimeOut() { qDebug()<<"time out.."; _timeOut->stop();
if (_file.isOpen()) { _file.close(); }
getFileFromURL(_url, _filePath); /* try again */ } void iHttpDownloadS::replyFinished(QNetworkReply* reply) /* download finished */ { _file.waitForBytesWritten(10000);/* wait 10s for write to file complete, can comment this */ if (0 == _file.size()) { qDebug()<<"Nothing be downloaded."; } else { /* add our updateUI code here... */ qDebug()<<"finished"; } } void iHttpDownloadS::replayDownloadProgress(qint64 done, qint64 total) /* downloading... */ { qDebug()<<QString("%1%").arg(done / (double)total * 100); if ((0 != _progressBar) && (0 != total)) { _progressBar->setMaximum(total); _progressBar->setValue(done); } } void iHttpDownloadS::slotReadyRead() /* if this is not been fired for 30s, we trate this timeout, and the timout handle will re download the file */ { _file.write(this->_reply->readAll()); if (_timeOut->isActive()) { _timeOut->stop(); } _timeOut->start(30000);/* wait 30 seconds */ } void iHttpDownloadS::slotError(QNetworkReply::NetworkError errorCode) /* handle error */ { qDebug()<<"error:"<<errorCode; setErrorMessage(QString("Error:NetworkError code:%1").arg(errorCode)); if (_file.isOpen()) { _file.close(); }
getFileFromURL(_url, _filePath);/* try again */ } |