1.首先在.pro文件中添加支持
QT += network
DownLoadFileHttps.h
#ifndef DOWNLOADFILEHTTPS_H
#define DOWNLOADFILEHTTPS_H
#include <memory>
#include <QObject>
#include <QUrl>
#include <QFile>
#include <QDir>
#include <QPointer>
#include <QApplication>
#include <QNetworkReply>
#include <QNetworkAccessManager>
#include <QStandardPaths>
#include "mainwindow.h"
class MainWindow;
class DownLoadFileHttps : public QObject
{
Q_OBJECT
public:
// 参数1=下载链接 参数2=保存的路径 参数3=父窗口地址
explicit DownLoadFileHttps(const QString& downloadUrl, const QString& savePath, QObject* parent = nullptr);
//析构,不解释
~DownLoadFileHttps();
bool startDownload(); // 开始下载文件
void cancelDownload(); // 取消下载文件
Q_SIGNALS:
// 下载进度信号
void sigProgress(qint64 bytesRead, qint64 totalBytes, qreal progress);
// 下载完成信号
void sigDownloadFinished();
private Q_SLOTS:
// QNetworkReply::finished对应的槽函数
void httpFinished();
// QIODevice::readyRead对应的槽函数
void httpReadyRead();
// QNetworkReply::downloadProgress对应的槽函数
void networkReplyProgress(qint64 bytesRead, qint64 totalBytes);
private:
void startRequest(const QUrl& requestedUrl);
std::unique_ptr<QFile> openFileForWrite(const QString& fileName);
private:
// 保存构造时传入的下载url
QString m_downloadUrl;
// 保存构造时传入的保存路径
QString m_savePath;
// 默认文件名称
const QString defaultFileName = "QConnect.exe";
QUrl url;
QNetworkAccessManager qnam;
QPointer<QNetworkReply> reply;
std::unique_ptr<QFile> m_fileptr;
bool httpRequestAborted;
MainWindow *m_mainwindow;
};
#endif // DOWNLOADFILEHTTPS_H
DownLoadFileHttps.cpp
#include "DownLoadFileHttps.h"
DownLoadFileHttps::DownLoadFileHttps(const QString& downloadUrl, const QString& savePath, QObject* parent)
: QObject(parent)
{
m_downloadUrl = downloadUrl;
m_savePath = savePath;
m_mainwindow = (MainWindow*)parent;
}
DownLoadFileHttps::~DownLoadFileHttps()
{
}
bool DownLoadFileHttps::startDownload()
{
const QUrl newUrl = QUrl::fromUserInput(m_downloadUrl);
if (!newUrl.isValid()) {
qDebug() << QString("Download failed: %1.").arg(reply->errorString());
return false;
}
QString svrloadFile = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation);
QString fileName = newUrl.fileName();
//判断文件名称是否正确
if (fileName.isEmpty())
{
fileName = defaultFileName;
}
//判断传有路径,没有则默认路径
if (m_savePath.isEmpty())
{
m_savePath = svrloadFile;
}
//判断路径是否存在,不存在创建
if (!QFileInfo(m_savePath).isDir())
{
QDir dir;
dir.mkpath(m_savePath);
}
fileName.prepend(m_savePath + '/');
if (QFile::exists(fileName))//判断是否存在此文件
{
QFile::remove(fileName);
}
m_fileptr = openFileForWrite(fileName);
if (!m_fileptr)
return false;
startRequest(newUrl);
return true;
}
void DownLoadFileHttps::cancelDownload()
{
httpRequestAborted = true;
reply->abort();
}
void DownLoadFileHttps::httpFinished()
{
QFileInfo fi;
if (m_fileptr) {
fi.setFile(m_fileptr->fileName());
m_fileptr->close();
m_fileptr.reset();
}
if (httpRequestAborted) {
return;
}
if (reply->error()) {
QFile::remove(fi.absoluteFilePath());
qDebug() << QString("Download failed: %1.").arg(reply->errorString());
return;
}
const QVariant redirectionTarget = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
if (!redirectionTarget.isNull()) {
const QUrl redirectedUrl = url.resolved(redirectionTarget.toUrl());
m_fileptr = openFileForWrite(fi.absoluteFilePath());
if (!m_fileptr)
{
return;
}
startRequest(redirectedUrl);
return;
}
Q_EMIT sigDownloadFinished();
Q_EMIT m_mainwindow->sigDownloadFinished();
}
void DownLoadFileHttps::httpReadyRead()
{
if (m_fileptr)
m_fileptr->write(reply->readAll());
}
void DownLoadFileHttps::networkReplyProgress(qint64 bytesRead, qint64 totalBytes)
{
qreal progress = qreal(bytesRead) / qreal(totalBytes);
Q_EMIT sigProgress(bytesRead, totalBytes, progress);
qDebug() << QString::number(progress * 100, 'f', 2) << "% "
<< bytesRead / (1024 * 1024) << "MB" << "/" << totalBytes / (1024 * 1024) << "MB";
emit m_mainwindow->sigProgress(bytesRead, totalBytes, progress);
}
void DownLoadFileHttps::startRequest(const QUrl& requestedUrl)
{
try {
url = requestedUrl;
httpRequestAborted = false;
QSslConfiguration config = QSslConfiguration::defaultConfiguration();
config.setProtocol(QSsl::AnyProtocol);
config.setPeerVerifyMode(QSslSocket::VerifyNone);
QNetworkRequest request = QNetworkRequest(url);
request.setSslConfiguration(config);
reply = qnam.get(request);
connect(reply, &QNetworkReply::finished, this, &DownLoadFileHttps::httpFinished);
connect(reply, &QIODevice::readyRead, this, &DownLoadFileHttps::httpReadyRead);
connect(reply, &QNetworkReply::downloadProgress, this, &DownLoadFileHttps::networkReplyProgress);
//qDebug() << QString(tr("Downloading %1...").arg(url.toString()));
}
catch (...)
{
return ;
}
}
std::unique_ptr<QFile> DownLoadFileHttps::openFileForWrite(const QString& fileName)
{
std::unique_ptr<QFile> file(new QFile(fileName));
if (!file->open(QIODevice::WriteOnly))
{
qDebug() << QString("Unable to save the file %1: %2.")
.arg(QDir::toNativeSeparators(fileName), file->errorString());
return nullptr;
}
return file;
}
mainwindow.ui
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>523</width>
<height>367</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<widget class="QWidget" name="horizontalLayoutWidget">
<property name="geometry">
<rect>
<x>40</x>
<y>40</y>
<width>411</width>
<height>41</height>
</rect>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>下载Url:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEdit"/>
</item>
<item>
<widget class="QPushButton" name="pushButton">
<property name="text">
<string>下载</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QProgressBar" name="progressBar">
<property name="geometry">
<rect>
<x>40</x>
<y>120</y>
<width>431</width>
<height>23</height>
</rect>
</property>
<property name="value">
<number>0</number>
</property>
</widget>
<widget class="QLabel" name="label_2">
<property name="geometry">
<rect>
<x>40</x>
<y>170</y>
<width>54</width>
<height>12</height>
</rect>
</property>
<property name="text">
<string>日志信息:</string>
</property>
</widget>
<widget class="QLabel" name="label_3">
<property name="geometry">
<rect>
<x>110</x>
<y>170</y>
<width>54</width>
<height>12</height>
</rect>
</property>
<property name="text">
<string/>
</property>
</widget>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>523</width>
<height>23</height>
</rect>
</property>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<resources/>
<connections/>
</ui>
MainWindow调用例子:
MainWindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QStandardPaths>
#include "DownLoadFileHttps.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
connect(this,SIGNAL(sigProgress(qint64, qint64, qreal)),this,SLOT(sltProgress(qint64, qint64, qreal)));
connect(this,SIGNAL(sigDownloadFinished()),this,SLOT(sltDownloadFinished()));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_clicked()
{
QString svrloadFile = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation);
DownLoadFileHttps* dT;
dT = new DownLoadFileHttps(ui->lineEdit->text(), svrloadFile,this);
dT->startDownload();
}
void MainWindow::sltProgress(qint64 bytesRead, qint64 totalBytes, qreal progress)
{
ui->progressBar->setValue(progress*100);
QString title = QString::number(progress*100,'f',2)+"% "+QString::number(bytesRead/(1024*1024),'f',2)+"MB/"+QString::number(totalBytes/(1024*1024),'f',2)+"MB";
ui->label_3->setText(title);
}
void MainWindow::sltDownloadFinished()
{
ui->label_3->setText(tr("下载完成:"));
}
MainWindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
signals:
void sigProgress(qint64 bytesRead, qint64 totalBytes, qreal progress); // 下载进度信号
void sigDownloadFinished(); // 下载完成信号
private slots:
void on_pushButton_clicked();
void sltProgress(qint64 bytesRead, qint64 totalBytes, qreal progress); // 下载进度信号
void sltDownloadFinished(); // 下载完成信号
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H