简述

在前面章节中我们讲述了关于Qt显示网络图片的内容,比较简单,因为图片一般都比较小,下载到本地速度比较快,所以基本不需要什么特殊处理,本节我们主要针对HTTP实现上传/下载进行详细的讲解与分享,包括:用户认证,实时获取下载大小、速度、剩余时间信息等。

首先看一下即将用到的公式:

文件剩余大小 = 文件总大小 - 文件已下载大小

平均速度 = 文件已下载大小 / 文件已下载大小所用的时间

瞬时速度 = 每秒下载的文件大小

剩余时间 = 文件剩余大小 / 瞬时速度

下面以下载为例,来实现一个文件下载管理器。

效果

QNetworkAccessManager

  1. DownloadNetworkManager::DownloadNetworkManager(QObject *parent)
  2. : QNetworkAccessManager(parent)
  3. {
  4. // 获取当前的时间戳,设置下载的临时文件名称
  5. QDateTime dateTime = QDateTime::currentDateTime();
  6. QString date = dateTime.toString("yyyy-MM-dd-hh-mm-ss-zzz");
  7. m_strFileName = QString("E:/%1.tmp").arg(date);
  8. connect(this, SIGNAL(finished(QNetworkReply *)), this, SLOT(replyFinished(QNetworkReply *)));
  9. }
  10. DownloadNetworkManager::~DownloadNetworkManager()
  11. {
  12. // 终止下载
  13. if (m_pReply != NULL)
  14. {
  15. m_pReply->abort();
  16. m_pReply->deleteLater();
  17. }
  18. }
  19. // 设置URL及消息头,开始请求
  20. void DownloadNetworkManager::execute()
  21. {
  22. m_url = QUrl("http://192.168.*.*/download/2.0.0.zip");
  23. QNetworkRequest request;
  24. request.setUrl(m_url);
  25. request.setHeader(QNetworkRequest::ContentTypeHeader, "application/zip");
  26. connect(this, SIGNAL(authenticationRequired(QNetworkReply *, QAuthenticator *)), this, SLOT(onAuthenticationRequest(QNetworkReply *, QAuthenticator *)));
  27. m_pReply = get(request);
  28. connect(m_pReply, SIGNAL(downloadProgress(qint64, qint64)), this, SIGNAL(downloadProgress(qint64, qint64)));
  29. connect(m_pReply, SIGNAL(readyRead()), this, SLOT(readyRead()));
  30. }
  31. void DownloadNetworkManager::replyFinished(QNetworkReply *reply)
  32. {
  33. // 获取响应的信息,状态码为200表示正常
  34. QVariant statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
  35. // 无错误返回
  36. if (reply->error() == QNetworkReply::NoError)
  37. {
  38. // 重命名临时文件
  39. QFileInfo fileInfo(m_strFileName);
  40. QFileInfo newFileInfo = fileInfo.absolutePath() + m_url.fileName();
  41. QDir dir;
  42. if (dir.exists(fileInfo.absolutePath()))
  43. {
  44. if (newFileInfo.exists())
  45. newFileInfo.dir().remove(newFileInfo.fileName());
  46. QFile::rename(m_strFileName, newFileInfo.absoluteFilePath());
  47. }
  48. }
  49. else
  50. {
  51. QString strError = reply->errorString();
  52. qDebug() << "Error:" << strError;
  53. }
  54. emit replyFinished(statusCode.toInt());
  55. }
  56. // 用户认证
  57. void DownloadNetworkManager::onAuthenticationRequest(QNetworkReply *reply, QAuthenticator *authenticator)
  58. {
  59. QByteArray password;
  60. password.append("123456");
  61. password = QByteArray::fromBase64(password);
  62. QString strPassword(password);
  63. authenticator->setUser("wang");
  64. authenticator->setPassword(strPassword);
  65. }
  66. // 本地写文件
  67. void DownloadNetworkManager::readyRead()
  68. {
  69. QFileInfo fileInfo(m_strFileName);
  70. QFileInfo newFileInfo = fileInfo.absolutePath() + m_url.fileName();
  71. QString strFileName = newFileInfo.absoluteFilePath();
  72. emit fileName(strFileName);
  73. // 写文件-形式为追加
  74. QFile file(m_strFileName);
  75. if (file.open(QIODevice::Append))
  76. file.write(m_pReply->readAll());
  77. file.close();
  78. }

使用

调用download()接口开始下载,关联downloadProgress信号和槽,可以实时获取下载大小、速度、剩余时间等信息。

  1. // 开始下载
  2. void MainWindow::download()
  3. {
  4. if (m_pNetworkManager == NULL)
  5. {
  6. m_pNetworkManager = new DownloadNetworkManager(this);
  7. connect(m_pNetworkManager, SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(downloadProgress(qint64, qint64)), Qt::QueuedConnection);
  8. connect(m_pNetworkManager, SIGNAL(replyFinished(int)), this, SLOT(replyFinished(int)), Qt::QueuedConnection);
  9. connect(m_pNetworkManager, SIGNAL(fileName(QString)), m_pFileInfoLabel, SLOT(setText(QString)), Qt::QueuedConnection);
  10. }
  11. m_pNetworkManager->execute();
  12. downloadTime.start();
  13. }
  14. // 计算下载大小、速度、剩余时间
  15. void MainWindow::downloadProgress(qint64 bytesReceived, qint64 bytesTotal)
  16. {
  17. // 总时间
  18. int nTime = downloadTime.elapsed();
  19. // 本次下载所用时间
  20. nTime -= m_nTime;
  21. // 下载速度
  22. double dBytesSpeed = (bytesReceived * 1000.0) / nTime;
  23. double dSpeed = dBytesSpeed;
  24. //剩余时间
  25. qint64 leftBytes = (bytesTotal - bytesReceived);
  26. double dLeftTime = (leftBytes * 1.0) / dBytesSpeed;
  27. m_pSpeedInfoLabel->setText(speed(dSpeed));
  28. m_pLeftTimeInfoLabel->setText(timeFormat(qCeil(dLeftTime)));
  29. m_pFileSizeInfoLabel->setText(size(bytesTotal));
  30. m_pDownloadInfoLabel->setText(size(bytesReceived));
  31. m_pProgressBar->setMaximum(bytesTotal);
  32. m_pProgressBar->setValue(bytesReceived);
  33. // 获取上一次的时间
  34. m_nTime = nTime;
  35. }
  36. // 下载完成
  37. void MainWindow::replyFinished(int statusCode)
  38. {
  39. m_nStatusCode = statusCode;
  40. QString strStatus = (statusCode == 200) ? QStringLiteral("下载成功") : QStringLiteral("下载失败");
  41. m_pStatusLabel->setText(strStatus);
  42. }

转换

下面是一些数据的格式转换,包括:字节转KB、MB、GB,速度转KB/S、MB/S、GB/S,秒转*d *h *m *s格式。

  1. // 字节转KB、MB、GB
  2. QString size(qint64 bytes)
  3. {
  4. QString strUnit;
  5. double dSize = bytes * 1.0;
  6. if (dSize <= 0)
  7. {
  8. dSize = 0.0;
  9. }
  10. else if (dSize < 1024)
  11. {
  12. strUnit = "Bytes";
  13. }
  14. else if (dSize < 1024 * 1024)
  15. {
  16. dSize /= 1024;
  17. strUnit = "KB";
  18. }
  19. else if (dSize < 1024 * 1024 * 1024)
  20. {
  21. dSize /= (1024 * 1024);
  22. strUnit = "MB";
  23. }
  24. else
  25. {
  26. dSize /= (1024 * 1024 * 1024);
  27. strUnit = "GB";
  28. }
  29. return QString("%1 %2").arg(QString::number(dSize, 'f', 2)).arg(strUnit);
  30. }
  31. // 速度转KB/S、MB/S、GB/S
  32. QString speed(double speed)
  33. {
  34. QString strUnit;
  35. if (speed <= 0)
  36. {
  37. speed = 0;
  38. strUnit = "Bytes/S";
  39. }
  40. else if (speed < 1024)
  41. {
  42. strUnit = "Bytes/S";
  43. }
  44. else if (speed < 1024 * 1024)
  45. {
  46. speed /= 1024;
  47. strUnit = "KB/S";
  48. }
  49. else if (speed < 1024 * 1024 * 1024)
  50. {
  51. speed /= (1024 * 1024);
  52. strUnit = "MB/S";
  53. }
  54. else
  55. {
  56. speed /= (1024 * 1024 * 1024);
  57. strUnit = "GB/S";
  58. }
  59. QString strSpeed = QString::number(speed, 'f', 2);
  60. return QString("%1 %2").arg(strSpeed).arg(strUnit);
  61. }
  62. // 秒转*d *h *m *s
  63. QString timeFormat(int seconds)
  64. {
  65. QString strValue;
  66. QString strSpacing(" ");
  67. if (seconds <= 0)
  68. {
  69. strValue = QString("%1s").arg(0);
  70. }
  71. else if (seconds < 60)
  72. {
  73. strValue = QString("%1s").arg(seconds);
  74. }
  75. else if (seconds < 60 * 60)
  76. {
  77. int nMinute = seconds / 60;
  78. int nSecond = seconds - nMinute * 60;
  79. strValue = QString("%1m").arg(nMinute);
  80. if (nSecond > 0)
  81. strValue += strSpacing + QString("%1s").arg(nSecond);
  82. }
  83. else if (seconds < 60 * 60 * 24)
  84. {
  85. int nHour = seconds / (60 * 60);
  86. int nMinute = (seconds - nHour * 60 * 60) / 60;
  87. int nSecond = seconds - nHour * 60 * 60 - nMinute * 60;
  88. strValue = QString("%1h").arg(nHour);
  89. if (nMinute > 0)
  90. strValue += strSpacing + QString("%1m").arg(nMinute);
  91. if (nSecond > 0)
  92. strValue += strSpacing + QString("%1s").arg(nSecond);
  93. }
  94. else
  95. {
  96. int nDay = seconds / (60 * 60 * 24);
  97. int nHour = (seconds - nDay * 60 * 60 * 24) / (60 * 60);
  98. int nMinute = (seconds - nDay * 60 * 60 * 24 - nHour * 60 * 60) / 60;
  99. int nSecond = seconds - nDay * 60 * 60 * 24 - nHour * 60 * 60 - nMinute * 60;
  100. strValue = QString("%1d").arg(nDay);
  101. if (nHour > 0)
  102. strValue += strSpacing + QString("%1h").arg(nHour);
  103. if (nMinute > 0)
  104. strValue += strSpacing + QString("%1m").arg(nMinute);
  105. if (nSecond > 0)
  106. strValue += strSpacing + QString("%1s").arg(nSecond);
  107. }
  108. return strValue;
  109. }

总结

一般来说,我们下载文件到本地,需要设置一个临时文件名,这里我以时间戳为名称外加.tmp来命名,当然更严格的最好再加上随机数,这样基本就不会出现重名情况。

下载时,首先判断本地文件中是否存在与下载文件同名的文件,如果有则删除,开始下载。当下载完成时,需要对临时文件重新命名。

以上内容比较详细,介绍了如何进行用户认证,如何实时获取下载大小、速度、剩余时间等信息,后面我们会针对断点续传来进行详细讲解,敬请期待!

Qt之HTTP上传/下载的更多相关文章

  1. Qt之HTTP上传/下载(继承QNetworkAccessManager,包括使用了authenticationRequired认证信号)

    效果 QNetworkAccessManager DownloadNetworkManager::DownloadNetworkManager(QObject *parent) : QNetworkA ...

  2. Selenium2学习-039-WebUI自动化实战实例-文件上传下载

    通常在 WebUI 自动化测试过程中必然会涉及到文件上传的自动化测试需求,而开发在进行相应的技术实现是不同的,粗略可划分为两类:input标签类(类型为file)和非input标签类(例如:div.a ...

  3. java客户端调用ftp上传下载文件

    1:java客户端上传,下载文件. package com.li.utils; import java.io.File; import java.io.FileInputStream; import ...

  4. Struts的文件上传下载

    Struts的文件上传下载 1.文件上传 Struts2的文件上传也是使用fileUpload的组件,这个组默认是集合在框架里面的.且是使用拦截器:<interceptor name=" ...

  5. 基于Spring Mvc实现的Excel文件上传下载

    最近工作遇到一个需求,需要下载excel模板,编辑后上传解析存储到数据库.因此为了更好的理解公司框架,我就自己先用spring mvc实现了一个样例. 基础框架 之前曾经介绍过一个最简单的spring ...

  6. Android okHttp网络请求之文件上传下载

    前言: 前面介绍了基于okHttp的get.post基本使用(http://www.cnblogs.com/whoislcj/p/5526431.html),今天来实现一下基于okHttp的文件上传. ...

  7. 用Canvas+Javascript FileAPI 实现一个跨平台的图片剪切、滤镜处理、上传下载工具

    直接上代码,其中上传功能需要自己配置允许跨域的文件服务器地址~ 或者将html文件贴到您的站点下同源上传也OK. 支持: 不同尺寸图片获取. 原图缩小放大. 原图移动. 选择框大小改变. 下载选中的区 ...

  8. Javaweb学习笔记——上传下载文件

    一.前言 在Javaweb中,上传下载是经常用到的功能,对于文件上传,浏览器在上传的过程中是以流的过程将文件传给服务器,一般都是使用commons-fileupload这个包实现上传功能,因为comm ...

  9. 服务器文件上传下载(XShell+Xftp)

    1.下载XShell安装包+Xftp安装包.百度网盘(XShell):https://pan.baidu.com/s/1eR4PFpS 百度网盘(Xftp):https://pan.baidu.com ...

随机推荐

  1. YARN-RPC

    运行在YARN平台上面的RPC. 当前存在非常多的开源RPC框架,比较著名的有Thrift.Protocol Buffers 和 AVRO.他们均有两部分构成:对象序列化和远程过程调用. 重要类: Y ...

  2. ASP.Net 上传进度条的实现方法

    对于加载时间比较长的ASP.NET页面,我们可以在客户端浏览器中显示进度条来显示页面正在装载.下面就是具体的实现过程: 新建项目,名字为WebPortal,在项目类型中选择Visual C#项目或者V ...

  3. associated 2 maps

    <!DOCTYPE html><html> <head> <meta http-equiv="Content-Type" content= ...

  4. eclipse sdk 无法更新

    最近祖国越来越强了,强得android开发工具都没法更新了,但是祖国再怎么强也阻挡不了我开发的脚步.下面给大家分享个更新android sdk 的方法.方法原理就是利用国内镜像源. 工具/原料 电脑一 ...

  5. MapReduce数据流向分析

    MR数据流向示意图 步骤 1 输入文件从HDFS流向Mapper节点.在一般情况下,map所需要的数据就存在本节点,这就是数据本地化计算的优势,但是往往集群中数据分布不均衡(1000台节点,数据冗余度 ...

  6. SQL技术内幕-6 rank()over(order by XX COLLATE) 的用法

    DECLARE @Names TABLE ( name VARCHAR(20) ); INSERT INTO @Names VALUES ('DeSzmetch'),('DESZMETCH'),('D ...

  7. hdu 4753 Fishhead’s Little Game 博弈论+记忆化搜索

    思路:状态最多有2^12,采用记忆化搜索!! 代码如下: #include<iostream> #include<stdio.h> #include<algorithm& ...

  8. poj 1568 Find the Winning Move 极大极小搜索

    思路:用极大极小搜索解决这样的问题很方便!! 代码如下: #include <cstdio> #include <algorithm> #define inf 10000000 ...

  9. C之算法

       1° 选择排序算法    核心思路如下图: 以字符串排序进行说明 #include <stdio.h> #include <string.h> #define SIZE ...

  10. Spring中RedirectAttributes对象重定向传参

    Spring3中的FlashAttribute 为 了防止用户刷新重复提交,save操作之后一般会redirect到另一个页面,同时带点操作成功的提示信息.因为是Redirect,Request里 的 ...