2024年最全Qt 之 HTTP 请求下载(支持断点续传)_qt http下载(2),头条面试C C++

img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上C C++开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以戳这里获取

    disconnect(m_reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onError(QNetworkReply::NetworkError)));
    m_reply->abort();
    m_reply->deleteLater();
    m_reply = NULL;
}

}

// 暂停下载按钮被按下,暂停当前下载;
void DownLoadManager::stopDownload()
{
// 这里m_isStop变量为了保护多次点击暂停下载按钮,导致m_bytesCurrentReceived 被不停累加;
if (!m_isStop)
{
//记录当前已经下载字节数
m_bytesCurrentReceived += m_bytesReceived;
stopWork();
}
}

// 重置参数;
void DownLoadManager::reset()
{
m_bytesCurrentReceived = 0;
m_bytesReceived = 0;
m_bytesTotal = 0;
}

// 删除文件;
void DownLoadManager::removeFile(QString fileName)
{
// 删除已下载的临时文件;
QFileInfo fileInfo(fileName);
if (fileInfo.exists())
{
QFile::remove(fileName);
}
}

// 停止下载按钮被按下,关闭下载,重置参数,并删除下载的临时文件;
void DownLoadManager::closeDownload()
{
stopWork();
reset();
removeFile(m_fileName);
}


### 2、MyHttpDownload



#include “myhttpdownload.h”
#include “downloadmanager.h”
#include

#define UNIT_KB 1024 //KB
#define UNIT_MB 1024*1024 //MB
#define UNIT_GB 1024*1024*1024 //GB

#define TIME_INTERVAL 300 //0.3s

MyHttpDownload::MyHttpDownload(QWidget *parent)
QWidget(parent)
, m_downloadManager(NULL)
, m_url(“”)
, m_timeInterval(0)
, m_currentDownload(0)
, m_intervalDownload(0)
{
ui.setupUi(this);
initWindow();
}

MyHttpDownload::~MyHttpDownload()
{

}

void MyHttpDownload::initWindow()
{
ui.progressBar->setValue(0);
connect(ui.pButtonStart, SIGNAL(clicked()), this, SLOT(onStartDownload()));
connect(ui.pButtonStop, SIGNAL(clicked()), this, SLOT(onStopDownload()));
connect(ui.pButtonClose, SIGNAL(clicked()), this, SLOT(onCloseDownload()));
// 进度条设置样式;
ui.progressBar->setStyleSheet("
QProgressBar
{
border-width: 0 10 0 10;
border-left: 1px, gray;
border-right: 1px, gray;
border-image:url(:/Resources/progressbar_back.png);
}
QProgressBar::chunk
{
border-width: 0 10 0 10;
border-image:url(:/Resources/progressbar.png);
}");
}

// 开始下载;
void MyHttpDownload::onStartDownload()
{
// 从界面获取下载链接;
m_url = ui.downloadUrl->text();
if (m_downloadManager == NULL)
{
m_downloadManager = new DownLoadManager(this);
connect(m_downloadManager , SIGNAL(signalDownloadProcess(qint64, qint64)), this, SLOT(onDownloadProcess(qint64, qint64)));
connect(m_downloadManager, SIGNAL(signalReplyFinished(int)), this, SLOT(onReplyFinished(int)));
}

// 这里先获取到m\_downloadManager中的url与当前的m\_url 对比,如果url变了需要重置参数,防止文件下载不全;
QString url = m_downloadManager->getDownloadUrl();
if (url != m_url)
{
    m_downloadManager->reset();
}
m_downloadManager->setDownInto(true);
m_downloadManager->downloadFile(m_url, "F:/MyHttpDownload/MyDownloadFile.zip");
m_timeRecord.start();
m_timeInterval = 0;
ui.labelStatus->setText(QStringLiteral("正在下载"));

}

// 暂停下载;
void MyHttpDownload::onStopDownload()
{
ui.labelStatus->setText(QStringLiteral(“停止下载”));
if (m_downloadManager != NULL)
{
m_downloadManager->stopDownload();
}
ui.labelSpeed->setText(“0 KB/S”);
ui.labelRemainTime->setText(“0s”);
}

// 关闭下载;
void MyHttpDownload::onCloseDownload()
{
m_downloadManager->closeDownload();
ui.progressBar->setValue(0);
ui.labelSpeed->setText(“0 KB/S”);
ui.labelRemainTime->setText(“0s”);
ui.labelStatus->setText(QStringLiteral(“关闭下载”));
ui.labelCurrentDownload->setText(“0 B”);
ui.labelFileSize->setText(“0 B”);
}

// 更新下载进度;
void MyHttpDownload::onDownloadProcess(qint64 bytesReceived, qint64 bytesTotal)
{
// 输出当前下载进度;
// 用到除法需要注意除0错误;
qDebug() << QString(“%1”).arg(bytesReceived * 100 / bytesTotal + 1);
// 更新进度条;
ui.progressBar->setMaximum(bytesTotal);
ui.progressBar->setValue(bytesReceived);

// m\_intervalDownload 为下次计算速度之前的下载字节数;
m_intervalDownload += bytesReceived - m_currentDownload;
m_currentDownload = bytesReceived;

uint timeNow = m_timeRecord.elapsed();

// 超过0.3s更新计算一次速度;
if (timeNow - m_timeInterval > TIME_INTERVAL)
{
    qint64 ispeed = m_intervalDownload * 1000 / (timeNow - m_timeInterval);
    QString strSpeed = transformUnit(ispeed, true);
    ui.labelSpeed->setText(strSpeed);
    // 剩余时间;
    qint64 timeRemain = (bytesTotal - bytesReceived) / ispeed;
    ui.labelRemainTime->setText(transformTime(timeRemain));

    ui.labelCurrentDownload->setText(transformUnit(m_currentDownload));
    ui.labelFileSize->setText(transformUnit(bytesTotal));

    m_intervalDownload = 0;
    m_timeInterval = timeNow;
}

}

// 下载完成;
void MyHttpDownload::onReplyFinished(int statusCode)
{
// 根据状态码判断当前下载是否出错;
if (statusCode >= 200 && statusCode < 400)
{
qDebug() << “Download Failed”;
}
else
{
qDebug() << “Download Success”;
}
}

// 转换单位;
QString MyHttpDownload::transformUnit(qint64 bytes , bool isSpeed)
{
QString strUnit = " B";
if (bytes <= 0)
{
bytes = 0;
}
else if (bytes < UNIT_KB)
{
}
else if (bytes < UNIT_MB)
{
bytes /= UNIT_KB;
strUnit = " KB";
}
else if (bytes < UNIT_GB)
{
bytes /= UNIT_MB;
strUnit = " MB";
}
else if (bytes > UNIT_GB)
{
bytes /= UNIT_GB;
strUnit = " GB";
}

if (isSpeed)
{
    strUnit += "/S";
}
return QString("%1%2").arg(bytes).arg(strUnit);

}

// 转换时间;
QString MyHttpDownload::transformTime(qint64 seconds)
{
QString strValue;
QString strSpacing(" “);
if (seconds <= 0)
{
strValue = QString(”%1s").arg(0);
}
else if (seconds < 60)
{
strValue = QString(“%1s”).arg(seconds);
}
else if (seconds < 60 * 60)
{
int nMinute = seconds / 60;
int nSecond = seconds - nMinute * 60;

    strValue = QString("%1m").arg(nMinute);

    if (nSecond > 0)
        strValue += strSpacing + QString("%1s").arg(nSecond);
}
else if (seconds < 60 * 60 * 24)
{
    int nHour = seconds / (60 * 60);
    int nMinute = (seconds - nHour * 60 * 60) / 60;
    int nSecond = seconds - nHour * 60 * 60 - nMinute * 60;

    strValue = QString("%1h").arg(nHour);

    if (nMinute > 0)
        strValue += strSpacing + QString("%1m").arg(nMinute);

    if (nSecond > 0)
        strValue += strSpacing + QString("%1s").arg(nSecond);
}
else
{
    int nDay = seconds / (60 * 60 * 24);
    int nHour = (seconds - nDay * 60 * 60 * 24) / (60 * 60);
    int nMinute = (seconds - nDay * 60 * 60 * 24 - nHour * 60 * 60) / 60;
    int nSecond = seconds - nDay * 60 * 60 * 24 - nHour * 60 * 60 - nMinute * 60;

    strValue = QString("%1d").arg(nDay);

    if (nHour > 0)
        strValue += strSpacing + QString("%1h").arg(nHour);

    if (nMinute > 0)
        strValue += strSpacing + QString("%1m").arg(nMinute);

    if (nSecond > 0)
        strValue += strSpacing + QString("%1s").arg(nSecond);
}

return strValue;

}


#### 标注: 代码注释中提到可以根据url来获取文件名,下方给予解释说明。



> 
> QString QUrl::fileName(ComponentFormattingOptions options = FullyDecoded) const   
>  Returns the name of the file, excluding the directory path.   
>  **Note that, if this QUrl object is given a path ending in a slash, the name of the file is considered empty.**   
>  If the path doesn’t contain any slash, it is fully returned as the fileName.
> 
> 
> 在Qt助手中我们找到此方法,根据加粗的字段可以看出fileName()方法也可能返回为空,所以不是都有效。
> 
> 
> 


好了,代码到此也就结束了,整体代码不算很难理解,也算是比较简单的一个http请求下载的小实例,后续我将会继续对http下载进行分析,具体包括将当前下载信息保存到本地、对http请求的文件进行分块下载等,欢迎大家一起交流。


#### [代码下载](https://bbs.csdn.net/topics/618668825)




---


## 尾


看代码其实实现起来不是那么难,但是一步想**把功能做全做完善**不是那么容易的事,我希望的是能够**尽善尽美**。在编码过程中也遇到了很多的问题包括下载速度的计算,下载信息的更新,与界面的交互这些都需要处理好。涉及到计算就要把握计算的值是否**正确**(或者说准确)以及是否计算结果越界导致程序**崩溃**。就如何控制下载速度的计算,我想不同的人有不同的思路,算出来的结果也不一定完全一致,但是大致时间段的速度应该是相近的,也可以用360等工具进行大致的测试。整篇文章的代码是经过不断地测试,改进之后的,代码中可能存在问题或者有一些不适当,如有还请高人指出。


![img](https://img-blog.csdnimg.cn/img_convert/34c6e6654c5cdd9a2db33499432b6b99.png)
![img](https://img-blog.csdnimg.cn/img_convert/42198de2864776e29e1a3d1e197496c4.png)

**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化的资料的朋友,可以添加戳这里获取](https://bbs.csdn.net/topics/618668825)**


**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

不适当,如有还请高人指出。


[外链图片转存中...(img-wXze9D8n-1715605569901)]
[外链图片转存中...(img-N2xgCu1G-1715605569902)]

**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化的资料的朋友,可以添加戳这里获取](https://bbs.csdn.net/topics/618668825)**


**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

  • 12
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
QT是一种跨平台的C++库,可以方便地进行ftp断点续传。FTP断点续传是指在文件传输过程中,当传输中断后,可以在下次传输时从中断的位置继续传输,而不需要重新传输整个文件。 在QT中实现ftp断点续传的关键是利用Qt的QNetworkAccessManager类和QNetworkReply类。首先,我们需要使用QNetworkAccessManager类建立与FTP服务器的连接,并发送GET命令获取文件。在QNetworkReply的finished()信号槽中可以检查文件的是否已下载完整,如果未完整下载,则可以通过设置Range请求头部来实现断点续传。这里的Range请求头部指定了从断点位置开始的字节数到文件末尾的字节数。 接下来,我们需要获取断点位置,可以通过QFile的size()方法获取已经下载的文件大小,然后将断点位置传递给FTP服务器。在Qt的QUrl的setEncodedQueryItem()方法中设置文件下载的起始位置。 等到下载完整个文件后,我们可以使用QFile类的seek()方法将文件指针移动到断点位置处,然后重新发起GET请求,继续从断点位置下载文件剩余部分。在QNetworkReply的finished()信号槽中,再次检查文件是否已下载完整,如果未完整下载,则继续进行断点续传。 通过以上步骤,我们就可以在QT中实现ftp断点续传功能。在实际应用中,我们还需要处理网络连接的中断、服务器断开连接等情况,以确保断点续传的可靠性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值