QT:多线程HTTP下载文件
这里的线程是指下载的通道(和操作系统中的线程不一样),一个线程就是一个文件的下载通道,多线程也就是同时开起好几个下载通道.当服务器提供下载服务时,使用下载者是共享带宽的,在优先级相同的情况下,总服务器会对总下载线程进行平均分配。不难理解,如果你线程多的话,那下载的越快。现流行的下载软件都支持多线程。
思路:
1:用阻塞的方式获取目标地址的HTTP头部,得到目标文件的大小。
2:算出每段文件的开始点,结尾点,并分别向目标地址发出请求。
3:每次目标地址有数据返回,都将得到的数据写入文件。
4:等待各段文件下载结果。
运行截图:

源代码:
- #include <QtCore>
- #include <QtNetwork>
- //多线程下载的线程数
- const int PointCount = 5;
- //目标文件的地址(千千静听的下载地址,我用来做实验的)
- const QString strUrl = "http://ttplayer.qianqian.com/otherdown/alladin/ttpsetup_5713.exe";
- //用于下载文件(或文件的一部分)
- class Download : public QObject
- {
- Q_OBJECT
- private:
- QNetworkAccessManager m_Qnam;
- QNetworkReply *m_Reply;
- QFile *m_File;
- const int m_Index;
- qint64 m_HaveDoneBytes;
- qint64 m_StartPoint;
- qint64 m_EndPoint;
- public:
- Download(int index, QObject *parent = 0);
- void StartDownload(const QUrl &url, QFile *file,
- qint64 startPoint=0, qint64 endPoint=-1);
- signals:
- void DownloadFinished();
- public slots:
- void FinishedSlot();
- void HttpReadyRead();
- };
- //用于管理文件的下载
- class DownloadControl : public QObject
- {
- Q_OBJECT
- private:
- int m_DownloadCount;
- int m_FinishedNum;
- int m_FileSize;
- QUrl m_Url;
- QFile *m_File;
- public:
- DownloadControl(QObject *parent = 0);
- void StartFileDownload(const QString &url, int count);
- qint64 GetFileSize(QUrl url);
- signals:
- void FileDownloadFinished();
- private slots:
- void SubPartFinished();
- };
- Download::Download(int index, QObject *parent)
- : QObject(parent), m_Index(index)
- {
- m_HaveDoneBytes = 0;
- m_StartPoint = 0;
- m_EndPoint = 0;
- m_File = NULL;
- }
- void Download::StartDownload(const QUrl &url,
- QFile *file,
- qint64 startPoint/* =0 */,
- qint64 endPoint/* =-1 */)
- {
- if( NULL == file )
- return;
- m_HaveDoneBytes = 0;
- m_StartPoint = startPoint;
- m_EndPoint = endPoint;
- m_File = file;
- //根据HTTP协议,写入RANGE头部,说明请求文件的范围
- QNetworkRequest qheader;
- qheader.setUrl(url);
- QString range;
- range.sprintf("Bytes=%lld-%lld", m_StartPoint, m_EndPoint);
- qheader.setRawHeader("Range", range.toAscii());
- //开始下载
- qDebug() << "Part " << m_Index << " start download";
- m_Reply = m_Qnam.get(QNetworkRequest(qheader));
- connect(m_Reply, SIGNAL(finished()),
- this, SLOT(FinishedSlot()));
- connect(m_Reply, SIGNAL(readyRead()),
- this, SLOT(HttpReadyRead()));
- }
- //下载结束
- void Download::FinishedSlot()
- {
- m_File->flush();
- m_Reply->deleteLater();
- m_Reply = 0;
- m_File = 0;
- qDebug() << "Part " << m_Index << " download finished";
- emit DownloadFinished();
- }
- void Download::HttpReadyRead()
- {
- if ( !m_File )
- return;
- //将读到的信息写入文件
- QByteArray buffer = m_Reply->readAll();
- m_File->seek( m_StartPoint + m_HaveDoneBytes );
- m_File->write(buffer);
- m_HaveDoneBytes += buffer.size();
- }
- //用阻塞的方式获取下载文件的长度
- qint64 DownloadControl::GetFileSize(QUrl url)
- {
- QNetworkAccessManager manager;
- qDebug() << "Getting the file size...";
- QEventLoop loop;
- //发出请求,获取目标地址的头部信息
- QNetworkReply *reply = manager.head(QNetworkRequest(url));
- QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit()), Qt::DirectConnection);
- loop.exec();
- QVariant var = reply->header(QNetworkRequest::ContentLengthHeader);
- reply->deleteLater();
- qint64 size = var.toLongLong();
- qDebug() << "The file size is: " << size;
- return size;
- }
- DownloadControl::DownloadControl(QObject *parent)
- : QObject(parent)
- {
- m_DownloadCount = 0;
- m_FinishedNum = 0;
- m_FileSize = 0;
- m_File = new QFile;
- }
- void DownloadControl::StartFileDownload(const QString &url, int count)
- {
- m_DownloadCount = count;
- m_FinishedNum = 0;
- m_Url = QUrl(url);
- m_FileSize = GetFileSize(m_Url);
- //先获得文件的名字
- QFileInfo fileInfo(m_Url.path());
- QString fileName = fileInfo.fileName();
- if (fileName.isEmpty())
- fileName = "index.html";
- m_File->setFileName(fileName);
- //打开文件
- m_File->open(QIODevice::WriteOnly);
- Download *tempDownload;
- //将文件分成PointCount段,用异步的方式下载
- qDebug() << "Start download file from " << strUrl;
- for(int i=0; i<m_DownloadCount; i++)
- {
- //先算出每段的开头和结尾(HTTP协议所需要的信息)
- int start = m_FileSize * i / m_DownloadCount;
- int end = m_FileSize * (i+1) / m_DownloadCount;
- if( i != 0 )
- start--;
- //分段下载该文件
- tempDownload = new Download(i+1, this);
- connect(tempDownload, SIGNAL(DownloadFinished()),
- this, SLOT(SubPartFinished()));
- connect(tempDownload, SIGNAL(DownloadFinished()),
- tempDownload, SLOT(deleteLater()));
- tempDownload->StartDownload(m_Url, m_File, start, end);
- }
- }
- void DownloadControl::SubPartFinished()
- {
- m_FinishedNum++;
- //如果完成数等于文件段数,则说明文件下载完毕,关闭文件,发生信号
- if( m_FinishedNum == m_DownloadCount )
- {
- m_File->close();
- emit FileDownloadFinished();
- qDebug() << "Download finished";
- }
- }
- #include "main.moc"
- int main(int argc, char **argv)
- {
- QCoreApplication app(argc, argv);
- //用阻塞的方式下载文件,完成后退出
- DownloadControl *control = new DownloadControl;
- QEventLoop loop;
- QObject::connect(control, SIGNAL(FileDownloadFinished()),
- &loop, SLOT(quit()));
- control->StartFileDownload(strUrl, PointCount);
- loop.exec();
- control->deleteLater();
- return 0;
- }
http://blog.csdn.net/small_qch/article/details/7223026
QT:多线程HTTP下载文件的更多相关文章
- win10环境下使用苹果虚拟机不要开多线程应用下载文件
win10环境下使用苹果虚拟机开多线程应用下载文件时候卡死,网络老掉. 8GB内存不够用?2.5mb网速不够用? 开的百度网盘下载个电影 结果虚拟机卡的不行 关了 网盘 挂起虚拟机 然后再 继续运行客 ...
- Python之FTP多线程下载文件之多线程分块下载文件
Python之FTP多线程下载文件之多线程分块下载文件 Python中的ftplib模块用于对FTP的相关操作,常见的如下载,上传等.使用python从FTP下载较大的文件时,往往比较耗时,如何提高从 ...
- Java多线程断点下载文件
Java实现断点续传+多线程下载 如下代码所示,每一步都有注解 思路: 通过URL连接到服务器上要下载的文件,得到文件的大小: 算出每条线程下载的开始位置和结束位置,例如,有两条线程下载100Byte ...
- java多线程批量下载文件
多线程下载文件 平时开发中有时会用到文件下载,为了提高文件的下载速率,采用多线程下载能够达到事半功倍的效果: package test; /** * 文件下载类 * @author luweichen ...
- android多线程断点续传下载文件
一.目标 1.多线程抢占服务器资源下载. 2.断点续传. 二.实现思路. 假设分为三个线程: 1.各个线程分别向服务器请求文件的不同部分. 这个涉及Http协议,可以在Header中使用Range参数 ...
- 通过Qt从URL下载文件
示例1: 通过Qt自带的例子学习,位置:[安装盘符]:\Qt\Qt5.1.1\5.1.1\Src\qtbase\examples\network\download 示例2: 通过Qt的文档,位置: ...
- Python之FTP多线程下载文件之分块多线程文件合并
Python之FTP多线程下载文件之分块多线程文件合并 欢迎大家阅读Python之FTP多线程下载系列之二:Python之FTP多线程下载文件之分块多线程文件合并,本系列的第一篇:Python之FTP ...
- java 多线程下载文件并实时计算下载百分比(断点续传)
多线程下载文件 多线程同时下载文件即:在同一时间内通过多个线程对同一个请求地址发起多个请求,将需要下载的数据分割成多个部分,同时下载,每个线程只负责下载其中的一部分,最后将每一个线程下载的部分组装起来 ...
- PHP利用Curl实现多线程抓取网页和下载文件
PHP 利用 Curl 可以完成各种传送文件操作,比如模拟浏览器发送GET,POST请求等等,然而因为php语言本身不支持多线程,所以开发爬虫程序效率并不高,一般采集 数据可以利用 PHPquery ...
随机推荐
- 开心菜鸟系列学习笔记------javascript(4)
一.全局上下文中的变量对象: 1)全局对象(Global object) 是在进入任何执行上下文之前就已经创建了的对象:这个对象只存在一份,它的属性在程序中任何地方都可以访问,全局对象的 ...
- 剑指offer-面试题2.实例Singleton模式
题目:设计一个类,我们只能生成该类的一个实例 这道题显然是对设计模式的考察,很明显是单例模式.什么是单例模式呢,就是就像题目所说的只能生成一 个类的实例.那么我们不难考虑到下面几点: 1.不能new多 ...
- 【转】Android LCD(四):LCD驱动调试篇
关键词:android LCD TFTSN75LVDS83B TTL-LVDS LCD电压背光电压 平台信息:内核:linux2.6/linux3.0系统:android/android4.0 平台 ...
- hdu 4355 Party All the Time(三分搜索)
Problem Description In the Dark forest, there is a Fairy kingdom where all the spirits will go toget ...
- ios常用的几个动画代码
#import "MianViewController.h" #import <QuartzCore/QuartzCore.h> @interface MianVi ...
- vector之妙用系列
vector用法: 总结了下大家写的,感觉用着很方便: vector是C++标准模板库中的部分内容,它是一个多功能的,能够操作多种数据结构和算法的模板类和函数库.vector之所以被认为是一个容器,是 ...
- Android漫游记(1)---内存映射镜像(memory maps)
Android系统内核基于Linux2.6+内核,因此,其在进程内存管理方面的非常多机制和Linux是非常相像的.首先,让我们来看一个典型的Android进程的内存镜像(App进程和Native本地进 ...
- 牵一发动全身【Nhibernate基本映射】
用牵一发动全身来形容Nhibernate的映射,一点都不夸张.小小的属性的修改,决定了整个Nhibernate的执行动态.以下让我们来详细了解一下,通过回想我们在上篇文章中用到的配置文件,做一个对xm ...
- 解决在Linux下安装Oracle时的中文乱码问题
本帖最后由 TsengYia 于 2012-2-22 17:06 编辑 解决在Linux下安装Oracle时的中文乱码问题 操作系统:Red Hat Enterprise Linux 6.1数据库:O ...
- Paxos算法深入分析
在分布式系统设计领域,Paxos可谓是最重要一致性的算法.Google的大牛们称 All working protocols for asynchronous consensus we have ...