这里的线程是指下载的通道(和操作系统中的线程不一样),一个线程就是一个文件的下载通道,多线程也就是同时开起好几个下载通道.当服务器提供下载服务时,使用下载者是共享带宽的,在优先级相同的情况下,总服务器会对总下载线程进行平均分配。不难理解,如果你线程多的话,那下载的越快。现流行的下载软件都支持多线程。

思路:
1:用阻塞的方式获取目标地址的HTTP头部,得到目标文件的大小。
2:算出每段文件的开始点,结尾点,并分别向目标地址发出请求。
3:每次目标地址有数据返回,都将得到的数据写入文件。

4:等待各段文件下载结果。

运行截图:

源代码:

    1. #include <QtCore>
    2. #include <QtNetwork>
    3. //多线程下载的线程数
    4. const int PointCount = 5;
    5. //目标文件的地址(千千静听的下载地址,我用来做实验的)
    6. const QString strUrl = "http://ttplayer.qianqian.com/otherdown/alladin/ttpsetup_5713.exe";
    7. //用于下载文件(或文件的一部分)
    8. class Download : public QObject
    9. {
    10. Q_OBJECT
    11. private:
    12. QNetworkAccessManager m_Qnam;
    13. QNetworkReply *m_Reply;
    14. QFile *m_File;
    15. const int m_Index;
    16. qint64 m_HaveDoneBytes;
    17. qint64 m_StartPoint;
    18. qint64 m_EndPoint;
    19. public:
    20. Download(int index, QObject *parent = 0);
    21. void StartDownload(const QUrl &url, QFile *file,
    22. qint64 startPoint=0, qint64 endPoint=-1);
    23. signals:
    24. void DownloadFinished();
    25. public slots:
    26. void FinishedSlot();
    27. void HttpReadyRead();
    28. };
    29. //用于管理文件的下载
    30. class DownloadControl : public QObject
    31. {
    32. Q_OBJECT
    33. private:
    34. int m_DownloadCount;
    35. int m_FinishedNum;
    36. int m_FileSize;
    37. QUrl m_Url;
    38. QFile *m_File;
    39. public:
    40. DownloadControl(QObject *parent = 0);
    41. void StartFileDownload(const QString &url, int count);
    42. qint64 GetFileSize(QUrl url);
    43. signals:
    44. void FileDownloadFinished();
    45. private slots:
    46. void SubPartFinished();
    47. };
    48. Download::Download(int index, QObject *parent)
    49. : QObject(parent), m_Index(index)
    50. {
    51. m_HaveDoneBytes = 0;
    52. m_StartPoint = 0;
    53. m_EndPoint = 0;
    54. m_File = NULL;
    55. }
    56. void Download::StartDownload(const QUrl &url,
    57. QFile *file,
    58. qint64 startPoint/* =0 */,
    59. qint64 endPoint/* =-1 */)
    60. {
    61. if( NULL == file )
    62. return;
    63. m_HaveDoneBytes = 0;
    64. m_StartPoint = startPoint;
    65. m_EndPoint = endPoint;
    66. m_File = file;
    67. //根据HTTP协议,写入RANGE头部,说明请求文件的范围
    68. QNetworkRequest qheader;
    69. qheader.setUrl(url);
    70. QString range;
    71. range.sprintf("Bytes=%lld-%lld", m_StartPoint, m_EndPoint);
    72. qheader.setRawHeader("Range", range.toAscii());
    73. //开始下载
    74. qDebug() << "Part " << m_Index << " start download";
    75. m_Reply = m_Qnam.get(QNetworkRequest(qheader));
    76. connect(m_Reply, SIGNAL(finished()),
    77. this, SLOT(FinishedSlot()));
    78. connect(m_Reply, SIGNAL(readyRead()),
    79. this, SLOT(HttpReadyRead()));
    80. }
    81. //下载结束
    82. void Download::FinishedSlot()
    83. {
    84. m_File->flush();
    85. m_Reply->deleteLater();
    86. m_Reply = 0;
    87. m_File = 0;
    88. qDebug() << "Part " << m_Index << " download finished";
    89. emit DownloadFinished();
    90. }
    91. void Download::HttpReadyRead()
    92. {
    93. if ( !m_File )
    94. return;
    95. //将读到的信息写入文件
    96. QByteArray buffer = m_Reply->readAll();
    97. m_File->seek( m_StartPoint + m_HaveDoneBytes );
    98. m_File->write(buffer);
    99. m_HaveDoneBytes += buffer.size();
    100. }
    101. //用阻塞的方式获取下载文件的长度
    102. qint64 DownloadControl::GetFileSize(QUrl url)
    103. {
    104. QNetworkAccessManager manager;
    105. qDebug() << "Getting the file size...";
    106. QEventLoop loop;
    107. //发出请求,获取目标地址的头部信息
    108. QNetworkReply *reply = manager.head(QNetworkRequest(url));
    109. QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit()), Qt::DirectConnection);
    110. loop.exec();
    111. QVariant var = reply->header(QNetworkRequest::ContentLengthHeader);
    112. reply->deleteLater();
    113. qint64 size = var.toLongLong();
    114. qDebug() << "The file size is: " << size;
    115. return size;
    116. }
    117. DownloadControl::DownloadControl(QObject *parent)
    118. : QObject(parent)
    119. {
    120. m_DownloadCount = 0;
    121. m_FinishedNum = 0;
    122. m_FileSize = 0;
    123. m_File = new QFile;
    124. }
    125. void DownloadControl::StartFileDownload(const QString &url, int count)
    126. {
    127. m_DownloadCount = count;
    128. m_FinishedNum = 0;
    129. m_Url = QUrl(url);
    130. m_FileSize = GetFileSize(m_Url);
    131. //先获得文件的名字
    132. QFileInfo fileInfo(m_Url.path());
    133. QString fileName = fileInfo.fileName();
    134. if (fileName.isEmpty())
    135. fileName = "index.html";
    136. m_File->setFileName(fileName);
    137. //打开文件
    138. m_File->open(QIODevice::WriteOnly);
    139. Download *tempDownload;
    140. //将文件分成PointCount段,用异步的方式下载
    141. qDebug() << "Start download file from " << strUrl;
    142. for(int i=0; i<m_DownloadCount; i++)
    143. {
    144. //先算出每段的开头和结尾(HTTP协议所需要的信息)
    145. int start = m_FileSize * i / m_DownloadCount;
    146. int end = m_FileSize * (i+1) / m_DownloadCount;
    147. if( i != 0 )
    148. start--;
    149. //分段下载该文件
    150. tempDownload = new Download(i+1, this);
    151. connect(tempDownload, SIGNAL(DownloadFinished()),
    152. this, SLOT(SubPartFinished()));
    153. connect(tempDownload, SIGNAL(DownloadFinished()),
    154. tempDownload, SLOT(deleteLater()));
    155. tempDownload->StartDownload(m_Url, m_File, start, end);
    156. }
    157. }
    158. void DownloadControl::SubPartFinished()
    159. {
    160. m_FinishedNum++;
    161. //如果完成数等于文件段数,则说明文件下载完毕,关闭文件,发生信号
    162. if( m_FinishedNum == m_DownloadCount )
    163. {
    164. m_File->close();
    165. emit FileDownloadFinished();
    166. qDebug() << "Download finished";
    167. }
    168. }
    169. #include "main.moc"
    170. int main(int argc, char **argv)
    171. {
    172. QCoreApplication app(argc, argv);
    173. //用阻塞的方式下载文件,完成后退出
    174. DownloadControl *control = new DownloadControl;
    175. QEventLoop loop;
    176. QObject::connect(control, SIGNAL(FileDownloadFinished()),
    177. &loop, SLOT(quit()));
    178. control->StartFileDownload(strUrl, PointCount);
    179. loop.exec();
    180. control->deleteLater();
    181. return 0;
    182. }

http://blog.csdn.net/small_qch/article/details/7223026

QT:多线程HTTP下载文件的更多相关文章

  1. win10环境下使用苹果虚拟机不要开多线程应用下载文件

    win10环境下使用苹果虚拟机开多线程应用下载文件时候卡死,网络老掉. 8GB内存不够用?2.5mb网速不够用? 开的百度网盘下载个电影 结果虚拟机卡的不行 关了 网盘 挂起虚拟机 然后再 继续运行客 ...

  2. Python之FTP多线程下载文件之多线程分块下载文件

    Python之FTP多线程下载文件之多线程分块下载文件 Python中的ftplib模块用于对FTP的相关操作,常见的如下载,上传等.使用python从FTP下载较大的文件时,往往比较耗时,如何提高从 ...

  3. Java多线程断点下载文件

    Java实现断点续传+多线程下载 如下代码所示,每一步都有注解 思路: 通过URL连接到服务器上要下载的文件,得到文件的大小: 算出每条线程下载的开始位置和结束位置,例如,有两条线程下载100Byte ...

  4. java多线程批量下载文件

    多线程下载文件 平时开发中有时会用到文件下载,为了提高文件的下载速率,采用多线程下载能够达到事半功倍的效果: package test; /** * 文件下载类 * @author luweichen ...

  5. android多线程断点续传下载文件

    一.目标 1.多线程抢占服务器资源下载. 2.断点续传. 二.实现思路. 假设分为三个线程: 1.各个线程分别向服务器请求文件的不同部分. 这个涉及Http协议,可以在Header中使用Range参数 ...

  6. 通过Qt从URL下载文件

    示例1: 通过Qt自带的例子学习,位置:[安装盘符]:\Qt\Qt5.1.1\5.1.1\Src\qtbase\examples\network\download   示例2: 通过Qt的文档,位置: ...

  7. Python之FTP多线程下载文件之分块多线程文件合并

    Python之FTP多线程下载文件之分块多线程文件合并 欢迎大家阅读Python之FTP多线程下载系列之二:Python之FTP多线程下载文件之分块多线程文件合并,本系列的第一篇:Python之FTP ...

  8. java 多线程下载文件并实时计算下载百分比(断点续传)

    多线程下载文件 多线程同时下载文件即:在同一时间内通过多个线程对同一个请求地址发起多个请求,将需要下载的数据分割成多个部分,同时下载,每个线程只负责下载其中的一部分,最后将每一个线程下载的部分组装起来 ...

  9. PHP利用Curl实现多线程抓取网页和下载文件

    PHP 利用 Curl  可以完成各种传送文件操作,比如模拟浏览器发送GET,POST请求等等,然而因为php语言本身不支持多线程,所以开发爬虫程序效率并不高,一般采集 数据可以利用 PHPquery ...

随机推荐

  1. html中的特殊符号表示法

    html中的特殊符号 符号 说明 编码   符号 说明 编码   符号 说明 编码 " 双引号 " × 乘号 × ← 向左箭头 ← & AND符号 & ÷ 除号 ÷ ...

  2. Oracle select 中case 的使用以及使用decode替换case

    表结构如下: 将money<50的显示为贫农,money<80的显示为中农,其他的显示为富农,sql 语句如下 select name, case then '贫农' then '中农' ...

  3. Css 小技巧总结

    相对偏移 指定left top等属性就能够够完美控制一个元素的位置 如: position:relative; left:2px; 今天遇到一个很好玩的问题,当两个并排浮动框,当一个框的长度太大时就会 ...

  4. 弄明白Android 接口回调机制

    以前对于这个机制理解不够深刻,现在重新整理下思路. 一.建模 我理解的接口回调就是,我这个类实现了一个接口里的方法doSomething,然后注册到你这里,然后我就去做别的事情去了,你在某个触发的时机 ...

  5. github page使用

    github page介绍: https://help.github.com/categories/20/articles 使用GitHub Pages建立博客 与GitHub建立好链接之后,就可以方 ...

  6. 【转】如何定制android源码的编译选项 & 后期安装? ---- 不错

    原文网址:http://blog.sina.com.cn/s/blog_3e3fcadd0100z3o9.html Android编译过程比较长,配置起来也很麻烦.现仅就工作遇到的问题做个总结.所用硬 ...

  7. Android APK安装包瘦身[转]

    很显然,APK安装包越小越好.下面从代码,资源文件,使用策略几个方面简要介绍下: 代码 保持良好的编程习惯,不要重复或者不用的代码,谨慎添加libs,移除使用不到的libs. 使用proguard混淆 ...

  8. UESTC_Palindromic String 2015 UESTC Training for Search Algorithm & String<Problem M>

    M - Palindromic String Time Limit: 3000/1000MS (Java/Others)     Memory Limit: 128000/128000KB (Java ...

  9. 51操作各种demo 驱动

    24C02 bit write=0; //写24C02的标志: sbit sda=P2^0; sbit scl=P2^1; void delay0() { ;; } void start() //开始 ...

  10. VS2015 MVC5项目部署

    刚看到一个年初的一个帖子说VS2015新建的MVC5项目部署后报错,自己捣鼓了一下,发现是Roslyn编译器的错误,简单处理后运行成功,分享如下: 新建一个MVC5的项目,保持不要动,执行以下几个步骤 ...