Qt的HTTP下载:
提示:这里可以添加要学的内容
最近一直在学习Qt,然后买的书是Qt 5.9开发指南,学习到HTTP下载的时候发现书里面的例程运行后怎么也下载不了东西,然后经过研究发现书里面有些东西欠缺,需要自己学习补齐。
UI界面如下:
具体工程代码
废话先不说直接贴代码!
工程文件
关于工程文件.pro的代码
QT += core gui
QT +=network //由于http是基于互联网的 所以要在工程文件中加入 network
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
CONFIG += c++17
# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
main.cpp \
htppmain.cpp
HEADERS += \
htppmain.h
FORMS += \
htppmain.ui
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
在工程文件中加入network组件
.h代码
#ifndef HTPPMAIN_H
#define HTPPMAIN_H
#include "qnetworkaccessmanager.h"
#include <QMainWindow>
#include <QFile>
#include <QUrl>
QT_BEGIN_NAMESPACE
namespace Ui { class HtppMain; }
QT_END_NAMESPACE
class HtppMain : public QMainWindow
{
Q_OBJECT
public:
HtppMain(QWidget *parent = nullptr);
~HtppMain();
private:
Ui::HtppMain *ui;
QNetworkAccessManager networkAccessManager;
QNetworkReply *reply;
QFile *download;
private slots:
void on_finished();
void on_readyRead();
void on_pushButton_2_clicked();
void on_pushButton_clicked();
};
#endif // HTPPMAIN_H
QNetworkAccessManager类
关于网络API的访问其实是基于QNetworkAccessManager类的,这个类可以保存发送的请求和一些配置,其中还包含了监视网络操作的各种信号。
QFile类
QFile是一种用于读写文本、二进制文件和资源的I/O的类
QNetworkReply类
QNetworkReply 类封装了使用 QNetworkAccessManager 发布的请求相关的回复信息。
QNetworkReply 是 QIODevice的子类,这意味着一旦从对象中读取数据,它就不再由设备保留。因此,如果需要,应用程序有责任保留这些数据。
每当从网络接收和处理更多数据时, readyRead () 信号被发射。
downloadProgress () 信号也被发射当接收数据时,但其中包含的字节数可能不表示实际接收字节数。
.cpp文件代码
#include "htppmain.h"
#include "ui_htppmain.h"
#include <QDir>
#include <QMessageBox>
#include <QNetworkReply>
HtppMain::HtppMain(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::HtppMain)
{
ui->setupUi(this);
}
HtppMain::~HtppMain()
{
delete ui;
}
//释放内存
void HtppMain::on_finished()
{
download->close();
delete download;
download = Q_NULLPTR;
reply->deleteLater(); //
reply = Q_NULLPTR;
}
//当有新数据时,文件将其写入
void HtppMain::on_readyRead()
{
download->write(reply->readAll());
}
void HtppMain::on_pushButton_2_clicked()
{
//当按钮按下时,获取程序的当前目录并且显示在UI界面
QString curPath=QDir::currentPath();
QString sub="temp";
ui->lineEdit_2->setText(curPath+'/'+sub+'/');
}
void HtppMain::on_pushButton_clicked()
{
//文本格式的Url
QString urlSpec =ui->lineEdit->text().trimmed();
if(urlSpec.isEmpty()){
QMessageBox::information(this,"error","请指定需要下载的URL");
return ;
}
//字符串转为Url格式
QUrl url=QUrl::fromUserInput(urlSpec);
if(!url.isValid()){
QMessageBox::information(this,"error","无效地址");
return ;
}
//判断路径是否为空 cleanPath可以使路径更简洁
QString tempDir=QDir::cleanPath(ui->lineEdit_2->text().trimmed());
if(tempDir.isEmpty()){
QMessageBox::information(this,"error","无效路径");
return;
}
//获取文件名字
QString fileName=url.fileName();
//判断路径是否为空和指向一个正确路径 并且通过prepend()函数将文件名与路径连接在一起形成一个完整路径
bool useDirectory = !tempDir.isEmpty() && QFileInfo(tempDir).isDir();
if(useDirectory)
fileName.prepend(tempDir+'/');
//如果路径中存在该文件
if (QFile::exists(fileName)) {
//选择覆盖掉文件则执行remove
if (QMessageBox::question(this, tr("Overwrite Existing File"),
tr("There already exists a file called %1%2."
" Overwrite?")
.arg(fileName,
useDirectory
? QString()
: QStringLiteral(" in the current directory")),
QMessageBox::Yes | QMessageBox::No,
QMessageBox::No)
== QMessageBox::No) {
return;
}
QFile::remove(fileName);
}
//创建一个路径与名字为fileName的临时文件,并且文件为只写类型
download=new QFile(fileName);
if(!download->open(QIODevice::WriteOnly)){
QMessageBox::information(this,"error","临时文件打开错误");
return;
}
//关联到url网络的请求(我自己这么理解)
reply = networkAccessManager.get(QNetworkRequest(url));
connect(reply,&QNetworkReply::finished,this,&HtppMain::on_finished);
connect(reply,&QIODevice::readyRead,this,&HtppMain::on_readyRead);
}
遇到的问题
在使用HTTP下载文件的过程中会出现ssl错误和下载文件大小一直是0kb的情况,
这种情况是由于Qt缺少相应的动态库文件,qt5.13以下需要在Qt安装目录找ssleay32.dll和libeay32.dll这两个文件
qt5.13以上版本则需要openssl的库,libssl-1_1.dll和libcrypto-1_1.dll库文件。
文件会在Qt安装目录的tool文件夹的对应编译器文件下,找不到可以搜索一下。
总结
HTTP下载的关键是Url地址正确并且转换为url格式,然后创建路径正式的文件,通过networkAccessManager获得Url的请求,然后将相关请求关联至自己的事件中,然后将数据写入文件最后释放内存。