Http下载-Qt4自带例子

本程序通过HTTP协议实现文件下载功能,支持HTTP与HTTPS协议,并具备断点续传、进度显示及错误处理等功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

//功能:输入要下载的文件的地址,就可以下载。
//main==========================================================
#include <QApplication>

#include "httpwindow.h"

int main(int argc, char *argv[])
{
QApplication app(argc, argv);
HttpWindow httpWin;
httpWin.show();
return httpWin.exec();
}
// httpwindow.h==================================================
#ifndef HTTPWINDOW_H
#define HTTPWINDOW_H

#include <QDialog>

QT_BEGIN_NAMESPACE
class QDialogButtonBox;
class QFile;
class QHttp;
class QHttpResponseHeader;
class QLabel;
class QLineEdit;
class QProgressDialog;
class QPushButton;
class QSslError;
class QAuthenticator;
QT_END_NAMESPACE

class HttpWindow : public QDialog
{
Q_OBJECT

public:
HttpWindow(QWidget *parent = 0);

private slots:
void downloadFile();           /*下载程序*/
void cancelDownload();
void httpRequestFinished(int requestId, bool error);        /*与信号requestFinished关联,捕捉每个完成信号*/
void readResponseHeader(const QHttpResponseHeader &responseHeader);            /*与信号responseHeaderReceived关联 ,   一连接上服务器就会收到此信号  */
void updateDataReadProgress(int bytesRead, int totalBytes           /*与信号dataReadProgress关联,显示进度*/
void enableDownloadButton();
void slotAuthenticationRequired(const QString &, quint16, QAuthenticator *);    /*与信号authenticationRequired关联,如果服务器要求验证,就显示登陆对话框,输入用户名密码 */
#ifndef QT_NO_OPENSSL
void sslErrors(const QList<QSslError> &errors);
#endif

private:
QLabel *statusLabel;
QLabel *urlLabel;
QLineEdit *urlLineEdit;
QProgressDialog *progressDialog;
QPushButton *downloadButton;
QPushButton *quitButton;
QDialogButtonBox *buttonBox;

QHttp *http;
QFile *file;
int httpGetId;
bool httpRequestAborted;
};

#endif
// httpwindow.cpp==========================
#include <QtGui>
#include <QtNetwork>

#include "httpwindow.h"
#include "ui_authenticationdialog.h"

HttpWindow::HttpWindow(QWidget *parent)
: QDialog(parent)
{
#ifndef QT_NO_OPENSSL
urlLineEdit = new QLineEdit("https://");
#else
urlLineEdit = new QLineEdit("http://");
#endif

urlLabel = new QLabel(tr("&URL:"));
urlLabel->setBuddy(urlLineEdit);
statusLabel = new QLabel(tr("Please enter the URL of a file you want to "
"download."));

downloadButton = new QPushButton(tr("Download"));
downloadButton->setDefault(true);
quitButton = new QPushButton(tr("Quit"));
quitButton->setAutoDefault(false);

buttonBox = new QDialogButtonBox;
buttonBox->addButton(downloadButton, QDialogButtonBox::ActionRole);
buttonBox->addButton(quitButton, QDialogButtonBox::RejectRole);

progressDialog = new QProgressDialog(this);

http = new QHttp(this);

connect(urlLineEdit, SIGNAL(textChanged(const QString &)),
this, SLOT(enableDownloadButton()));
connect(http, SIGNAL(requestFinished(int, bool)),
this, SLOT(httpRequestFinished(int, bool)));
connect(http, SIGNAL(dataReadProgress(int, int)),
this, SLOT(updateDataReadProgress(int, int)));
connect(http, SIGNAL(responseHeaderReceived(const QHttpResponseHeader &)),
this, SLOT(readResponseHeader(const QHttpResponseHeader &)));
connect(http, SIGNAL(authenticationRequired(const QString &, quint16, QAuthenticator *)),
this, SLOT(slotAuthenticationRequired(const QString &, quint16, QAuthenticator *)));
#ifndef QT_NO_OPENSSL
connect(http, SIGNAL(sslErrors(const QList<QSslError> &)),
this, SLOT(sslErrors(const QList<QSslError> &)));
#endif
connect(progressDialog, SIGNAL(canceled()), this, SLOT(cancelDownload()));
connect(downloadButton, SIGNAL(clicked()), this, SLOT(downloadFile()));
connect(quitButton, SIGNAL(clicked()), this, SLOT(close()));

QHBoxLayout *topLayout = new QHBoxLayout;
topLayout->addWidget(urlLabel);
topLayout->addWidget(urlLineEdit);

QVBoxLayout *mainLayout = new QVBoxLayout;
mainLayout->addLayout(topLayout);
mainLayout->addWidget(statusLabel);
mainLayout->addWidget(buttonBox);
setLayout(mainLayout);

setWindowTitle(tr("HTTP"));
urlLineEdit->setFocus();
}

void HttpWindow::downloadFile()     /*根据输入的地址下载文件,可以移植*/
{
QUrl url(urlLineEdit->text());
QFileInfo fileInfo(url.path());
QString fileName = fileInfo.fileName();
if (fileName.isEmpty())    /*如果没有输入文件名,就下载页面*/
fileName = "index.html";

if (QFile::exists(fileName)) {   /*如果文件已经存在,提示是否覆盖*/
if (QMessageBox::question(this, tr("HTTP"),
tr("There already exists a file called %1 in "
"the current directory. Overwrite?").arg(fileName),
QMessageBox::Ok|QMessageBox::Cancel, QMessageBox::Cancel)
== QMessageBox::Cancel)
return;
QFile::remove(fileName);   /*如果选覆盖,则先删除该文件*/
}

file = new QFile(fileName);
if (!file->open(QIODevice::WriteOnly)) {
QMessageBox::information(this, tr("HTTP"),
tr("Unable to save the file %1: %2.")
.arg(fileName).arg(file->errorString()));
delete file;
file = 0;
return;
}

QHttp::ConnectionMode mode = url.scheme().toLower() == "https" ? QHttp::ConnectionModeHttps : QHttp::ConnectionModeHttp; /*模式选择,是https, 还是http*/
http->setHost(url.host(), mode, url.port() == -1 ? 80 : url.port()); /*端口选择,如果没有填端口,取80*/

if (!url.userName().isEmpty())     /*如果已经输入了用户名密码,在这里赋值*/
http->setUser(url.userName(), url.password());   

httpRequestAborted = false;
QByteArray path = QUrl::toPercentEncoding(url.path(), "!$&'()*+,;=:@/");    /*转换编码 */
if (path.isEmpty())
path = "/";
httpGetId = http->get(path, file);    /*下载,语句立即返回,直到下载完成产生信号*/

progressDialog->setWindowTitle(tr("HTTP"));
progressDialog->setLabelText(tr("Downloading %1.").arg(fileName));
downloadButton->setEnabled(false);
}

void HttpWindow::cancelDownload()
{
statusLabel->setText(tr("Download canceled."));
httpRequestAborted = true;
http->abort();
downloadButton->setEnabled(true);
}

void HttpWindow::httpRequestFinished(int requestId, bool error)    /*捕捉任务完成信号,做后续处理*/
{
if (requestId != httpGetId)
return;
if (httpRequestAborted) {
if (file) {
file->close();
file->remove();
delete file;
file = 0;
}

progressDialog->hide();
return;
}

if (requestId != httpGetId)
return;

progressDialog->hide();
file->close();

if (error) {
file->remove();
QMessageBox::information(this, tr("HTTP"),
tr("Download failed: %1.")
.arg(http->errorString()));
} else {
QString fileName = QFileInfo(QUrl(urlLineEdit->text()).path()).fileName();
statusLabel->setText(tr("Downloaded %1 to current directory.").arg(fileName));
}

downloadButton->setEnabled(true);
delete file;
file = 0;
}

void HttpWindow::readResponseHeader(const QHttpResponseHeader &responseHeader)
/*连接服务器时会收到信号,进入此信号关联槽*/
{
switch (responseHeader.statusCode()) {
case 200:                   // Ok      /*404是没有此资源*/
case 301:                   // Moved Permanently
case 302:                   // Found
case 303:                   // See Other
case 307:                   // Temporary Redirect
// these are not error conditions
break;

default:
QMessageBox::information(this, tr("HTTP"),
tr("Download failed: %1.")
.arg(responseHeader.reasonPhrase()));
httpRequestAborted = true;
progressDialog->hide();
http->abort();
}
}

void HttpWindow::updateDataReadProgress(int bytesRead, int totalBytes)   /*显示进度*/
{
if (httpRequestAborted)
return;

progressDialog->setMaximum(totalBytes);
progressDialog->setValue(bytesRead);
}

void HttpWindow::enableDownloadButton()
{
downloadButton->setEnabled(!urlLineEdit->text().isEmpty());
}

void HttpWindow::slotAuthenticationRequired(const QString &hostName, quint16, QAuthenticator *authenticator)   
/*如果服务器要求用户名密码,跳出此信号关联槽,跳出一个已经画好的窗口Ui::Dialog 。可移植*/
{
QDialog dlg;
Ui::Dialog ui;
ui.setupUi(&dlg);
dlg.adjustSize();
ui.siteDescription->setText(tr("%1 at %2").arg(authenticator->realm()).arg(hostName));

if (dlg.exec() == QDialog::Accepted) {
authenticator->setUser(ui.userEdit->text());
authenticator->setPassword(ui.passwordEdit->text());
}
}

#ifndef QT_NO_OPENSSL
void HttpWindow::sslErrors(const QList<QSslError> &errors)
{
QString errorString;
foreach (const QSslError &error, errors) {
if (!errorString.isEmpty())
errorString += ", ";
errorString += error.errorString();
}

if (QMessageBox::warning(this, tr("HTTP Example"),
tr("One or more SSL errors has occurred: %1").arg(errorString),
QMessageBox::Ignore | QMessageBox::Abort) == QMessageBox::Ignore) {
http->ignoreSslErrors();
}
}
#endif