当前位置: 首页 > news >正文

开源 C++ QT Widget 开发(八)网络--Http文件下载

 文章的目的为了记录使用C++ 进行QT Widget 开发学习的经历。临时学习,完成app的开发。开发流程和要点有些记忆模糊,赶紧记录,防止忘记。

  相关链接:

开源 C++ QT Widget 开发(一)工程文件结构-CSDN博客

开源 C++ QT Widget 开发(二)基本控件应用-CSDN博客

开源 C++ QT Widget 开发(三)图表--波形显示器-CSDN博客

开源 C++ QT Widget 开发(四)文件--二进制文件查看编辑-CSDN博客

 开源 C++ QT Widget 开发(五)通讯--串口调试-CSDN博客

开源 C++ QT Widget 开发(六)通讯--TCP调试-CSDN博客

开源 C++ QT Widget 开发(七)线程--多线程及通讯-CSDN博客

开源 C++ QT Widget 开发(八)网络--Http文件下载-CSDN博客



推荐链接:

开源 java android app 开发(一)开发环境的搭建-CSDN博客

开源 java android app 开发(二)工程文件结构-CSDN博客

开源 java android app 开发(三)GUI界面布局和常用组件-CSDN博客

开源 java android app 开发(四)GUI界面重要组件-CSDN博客

开源 java android app 开发(五)文件和数据库存储-CSDN博客

开源 java android app 开发(六)多媒体使用-CSDN博客

开源 java android app 开发(七)通讯之Tcp和Http-CSDN博客

开源 java android app 开发(八)通讯之Mqtt和Ble-CSDN博客

开源 java android app 开发(九)后台之线程和服务-CSDN博客

开源 java android app 开发(十)广播机制-CSDN博客

开源 java android app 开发(十一)调试、发布-CSDN博客

开源 java android app 开发(十二)封库.aar-CSDN博客

推荐链接:

开源C# .net mvc 开发(一)WEB搭建_c#部署web程序-CSDN博客

开源 C# .net mvc 开发(二)网站快速搭建_c#网站开发-CSDN博客

开源 C# .net mvc 开发(三)WEB内外网访问(VS发布、IIS配置网站、花生壳外网穿刺访问)_c# mvc 域名下不可訪問內網,內網下可以訪問域名-CSDN博客

开源 C# .net mvc 开发(四)工程结构、页面提交以及显示_c#工程结构-CSDN博客

开源 C# .net mvc 开发(五)常用代码快速开发_c# mvc开发-CSDN博客

本章主要内容:基于 Qt Http 的网络文件下载器。
        

目录:

1.主要内容

2.核心源码分析

3.所有源码

4.显示效果

一、主要内容

        使用 QNetworkAccessManager 来处理 HTTP 请求,实现了文件的下载、进度显示、取消下载以及重定向处理等功能。DownloadTool 类封装了所有下载相关的核心逻辑,而 Widget 类则提供了一个简单的界面来触发下载操作。

二、核心源码分析

2.1  头文件部分
继承关系:继承自QObject,支持Qt的信号槽机制

网络组件:使用QNetworkAccessManager和QNetworkReply处理网络请求

内存管理:使用std::unique_ptr智能指针管理文件对象

线程安全:使用QPointer防止悬挂指针问题

2.2  主要功能

// 构造函数:接收下载URL和保存路径
DownloadTool(const QString& downloadUrl, const QString& savePath, QObject* parent = nullptr);

// 开始下载
void startDownload();

// 取消下载  
void cancelDownload();

// 信号:进度更新和完成通知
void sigProgress(qint64 bytesRead, qint64 totalBytes, qreal progress);
void sigDownloadFinished();


2.3  实现细节分析
下载流程:

startDownload() 验证URL并准备文件路径

startRequest() 发起网络请求并连接信号槽

httpReadyRead() 实时写入接收到的数据

networkReplyProgress() 更新下载进度

httpFinished() 处理下载完成或错误

关键特性:

✅ 自动创建保存目录

✅ 支持文件重命名(使用URL中的文件名)

✅ 自动处理重定向

✅ 错误处理和资源清理

✅ 进度实时反馈

4. 使用示例


// 创建下载器
DownloadTool* downloader = new DownloadTool("http://example.com/file.zip", "/path/to/save"
);// 连接信号
connect(downloader, &DownloadTool::sigProgress, [](qint64 bytes, qint64 total, qreal progress) {qDebug() << "Progress:" << progress * 100 << "%";
});connect(downloader, &DownloadTool::sigDownloadFinished, []() {qDebug() << "Download finished!";
});// 开始下载
downloader->startDownload();

三、所有源码

3.1  .pro文件

d#-------------------------------------------------
#
# Project created by QtCreator 2024-01-19T15:33:43
#
#-------------------------------------------------QT       += core gui
QT       += core gui network
greaterThan(QT_MAJOR_VERSION, 4): QT += widgetsTARGET = DownloadTool
TEMPLATE = app# The following define makes your csssompiler emit warnings if you use
# any feature of Qt which as been marked as deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS# You can also make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0SOURCES += \main.cpp \widget.cpp \downloadtool.cppHEADERS += \widget.h \downloadtool.hFORMS += \widget.ui

3.2  downloadTool.h

#ifndef DOWNLOADTOOL_H
#define DOWNLOADTOOL_H
#pragma once#include <QObject>        // QObject类是Qt对象模型的核心
#include <QUrl>           // QUrl类提供了使用URL的便捷接口
#include <QFile>          // QFile类用于对文件进行读写操作
#include <QDir>           // QDir类用于操作路径名及底层文件系统
#include <QPointer>       // QPointer指针引用的对象被销毁时候,会自动指向NULL,解决指针悬挂问题
#include <QApplication>   // 此处用于获取当前程序绝对路径
#include <QtNetwork/QNetworkReply>#include <QtNetwork/QNetworkAccessManager>  // QNetworkAccessManager类为应用提供发送网络请求和接收答复的API接口
#include <memory>         // 使用std::unique_ptr需要包含该头文件#define DOWNLOAD_DEBUG    // 是否打印输出class DownloadTool : public QObject  // 继承QObject
{Q_OBJECT              // 加入此宏,才能使用QT中的signal和slot机制public:// 构造函数参数:  1)http文件完整的url  2)保存的路径explicit DownloadTool(const QString& downloadUrl, const QString& savePath, QObject* parent = nullptr);~DownloadTool();void startDownload();  // 开始下载文件void cancelDownload(); // 取消下载文件Q_SIGNALS:void sigProgress(qint64 bytesRead, qint64 totalBytes, qreal progress);  // 下载进度信号void sigDownloadFinished();  // 下载完成信号private Q_SLOTS:void httpFinished();    // QNetworkReply::finished对应的槽函数void httpReadyRead();   // QIODevice::readyRead对应的槽函数void networkReplyProgress(qint64 bytesRead, qint64 totalBytes);  // QNetworkReply::downloadProgress对应的槽函数private:void startRequest(const QUrl& requestedUrl);std::unique_ptr<QFile> openFileForWrite(const QString& fileName);private:QString m_downloadUrl;  // 保存构造时传入的下载urlQString m_savePath;     // 保存构造时传入的保存路径const QString defaultFileName = "tmp";  // 默认下载到tmp文件夹QUrl url;QNetworkAccessManager qnam;QPointer<QNetworkReply> reply;std::unique_ptr<QFile> file;bool httpRequestAborted;
};#endif // DOWNLOADTOOL_H

3.3  downloadTool.cpp

#include "DownloadTool.h"DownloadTool::DownloadTool(const QString& downloadUrl, const QString& savePath, QObject* parent): QObject(parent)
{m_downloadUrl = downloadUrl;m_savePath    = savePath;
}DownloadTool::~DownloadTool() {}void DownloadTool::startDownload()
{const QUrl newUrl = QUrl::fromUserInput(m_downloadUrl);if (!newUrl.isValid()) {
#ifdef DOWNLOAD_DEBUGqDebug() << QString("Invalid URL: %1: %2").arg(m_downloadUrl, newUrl.errorString());
#endif // DOWNLOAD_DEBUGreturn;}QString fileName = newUrl.fileName();if (fileName.isEmpty()) fileName = defaultFileName;if (m_savePath.isEmpty()) { m_savePath = QApplication::applicationDirPath() + "/tmp"; }if (!QFileInfo(m_savePath).isDir()) {QDir dir;dir.mkpath(m_savePath);}fileName.prepend(m_savePath + '/');if (QFile::exists(fileName)) { QFile::remove(fileName); }file = openFileForWrite(fileName);if (!file) return;startRequest(newUrl);
}void DownloadTool::cancelDownload()
{httpRequestAborted = true;reply->abort();
}void DownloadTool::httpFinished()
{QFileInfo fi;if (file) {fi.setFile(file->fileName());file->close();file.reset();}if (httpRequestAborted) {return;}if (reply->error()) {QFile::remove(fi.absoluteFilePath());
#ifdef DOWNLOAD_DEBUGqDebug() << QString("Download failed: %1.").arg(reply->errorString());
#endif // DOWNLOAD_DEBUGreturn;}const QVariant redirectionTarget = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);if (!redirectionTarget.isNull()) {const QUrl redirectedUrl = url.resolved(redirectionTarget.toUrl());file = openFileForWrite(fi.absoluteFilePath());if (!file) { return; }startRequest(redirectedUrl);return;}Q_EMIT sigDownloadFinished();#ifdef DOWNLOAD_DEBUGqDebug() << QString(tr("Downloaded %1 bytes to %2 in %3").arg(fi.size()).arg(fi.fileName(), QDir::toNativeSeparators(fi.absolutePath())));qDebug() << "Finished";
#endif // DOWNLOAD_DEBUG
}void DownloadTool::httpReadyRead()
{if (file) file->write(reply->readAll());
}void DownloadTool::networkReplyProgress(qint64 bytesRead, qint64 totalBytes)
{qreal progress = qreal(bytesRead) / qreal(totalBytes);Q_EMIT sigProgress(bytesRead, totalBytes, progress);#ifdef DOWNLOAD_DEBUGqDebug() << QString::number(progress * 100, 'f', 2) << "%    "<< bytesRead / (1024 * 1024) << "MB" << "/" << totalBytes / (1024 * 1024) << "MB";
#endif // DOWNLOAD_DEBUG
}void DownloadTool::startRequest(const QUrl& requestedUrl)
{url = requestedUrl;httpRequestAborted = false;reply = qnam.get(QNetworkRequest(url));connect(reply, &QNetworkReply::finished, this, &DownloadTool::httpFinished);connect(reply, &QIODevice::readyRead, this, &DownloadTool::httpReadyRead);connect(reply, &QNetworkReply::downloadProgress, this, &DownloadTool::networkReplyProgress);#ifdef DOWNLOAD_DEBUGqDebug() << QString(tr("Downloading %1...").arg(url.toString()));
#endif // DOWNLOAD_DEBUG
}std::unique_ptr<QFile> DownloadTool::openFileForWrite(const QString& fileName)
{std::unique_ptr<QFile> file(new QFile(fileName));if (!file->open(QIODevice::WriteOnly)) {
#ifdef DOWNLOAD_DEBUGqDebug() << QString("Unable to save the file %1: %2.").arg(QDir::toNativeSeparators(fileName), file->errorString());
#endif // DOWNLOAD_DEBUGreturn nullptr;}return file;
}

3.4  widget.h

#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>namespace Ui {
class Widget;
}class Widget : public QWidget
{Q_OBJECTpublic:explicit Widget(QWidget *parent = 0);~Widget();private slots:void on_btnDown_clicked();private:Ui::Widget *ui;
};#endif // WIDGET_H

3.5  widget.cpp文件

#include "widget.h"
#include "ui_widget.h"
#include "DownloadTool.h"
Widget::Widget(QWidget *parent) :QWidget(parent),ui(new Ui::Widget)
{ui->setupUi(this);}Widget::~Widget()
{delete ui;
}void Widget::on_btnDown_clicked()
{DownloadTool* dT;//dT = new DownloadTool("https://desktop.docker.com/win/main/amd64/Docker%20Desktop%20Installer.exe", QApplication::applicationDirPath() + "/download");dT = new DownloadTool("https://dl.360safe.com/pclianmeng/n/3__3112523__3f7372633d6c6d266c733d6e33366163663466393961__68616f2e3336302e636e__0cd2.exe", QApplication::applicationDirPath() + "/download");dT->startDownload();
}

3.6  main.cpp

#include "widget.h"
#include <QApplication>int main(int argc, char *argv[])
{QApplication a(argc, argv);Widget w;w.show();return a.exec();
}

四、显示效果

点击下载,下载360卫士的exe文件,同时打印下载进度。

文件下载的位置

http://www.xdnf.cn/news/1399141.html

相关文章:

  • 《微服务架构从故障频发到自愈可控的实战突围方案》
  • CSDN博客语法(不常用但有用)
  • 谷歌 “Nano Banana“ 深度解析:AI 图像的未来是精准编辑,而非从零生成
  • ⚡ Linux find 命令参数详解
  • MySQL基础理解入门
  • 嵌入式硬件电路分析---AD采集电路
  • Spring Boot 自动配置原理深度解析:从启动流程到监听机制
  • 【Java EE进阶 --- SpringBoot】Spring Web MVC(Spring MVC)(二)
  • 设计模式之代理模式!
  • 深度学习基础:前馈网络、反向传播与梯度问题
  • 基于IEC61499开放自动化PLC数据储存方案
  • 在 WSL2-NVIDIA-Workbench 中安装Anaconda、CUDA 13.0、cuDNN 9.12 及 PyTorch(含完整环境验证)
  • 第 8 篇:量化交易之tradeUI和webserverUI 区别?
  • 系统分析师考试大纲新旧版本深度分析与备考策略
  • 捡捡java——2、基础07
  • 开发指南136-设置零值不显示
  • vue中的与,或,非
  • Ansible 核心运维场景落地:YUM 仓库、SSH 公钥、固定 IP 配置技巧
  • [Windows] 剪映国际版CapCut 6.7.0 视频编辑处理,免费使用素材和滤镜
  • 拼团小程序源码分享拼团余额提现小程序定制教程开发源码二开
  • LeetCode 136. 只出现一次的数字
  • [论文阅读] 人工智能 + 软件工程 | 从“法律条文”到“Gherkin脚本”:Claude与Llama谁更懂合规开发?
  • 普蓝自研AutoTrack-4X导航套件平台适配高校机器人实操应用
  • k8s(自写)
  • docker安装Prometheus和Grafana 监控界面
  • 为多种业态注入智能化发展新活力的智慧地产开源了
  • 从Java全栈开发视角看企业级应用架构设计与实践
  • C++转置正方形矩阵
  • 掌握表单:React中的受控组件与表单处理
  • 【物联网】BLE 系统架构全景图