Http协议的断点续传下载器,使用观察者模式监视下载进度,使用xml保存下载进度。
下载使用Http协议,为了做到断点续传,在点击暂停后,将已下载的大小等数据通过Json存入xml中,当继续传输的时候从xml文件中读取大小继续下载(好几个月前写的,真的想不起来了)
bool CHttpDownLoader::DownLoadData(LPCTSTR downloadedUrl, LPCTSTR strSavePath, LPCTSTR configFile)
{
m_InternetSession = new CInternetSession(HTTPINFO, , INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, INTERNET_FLAG_DONT_CACHE);
CString strServer;
CString strObject;
DWORD dw;
INTERNET_PORT nPort;
CString strFilePath;
CFileStatus fileStatus;
DWORD start;
DWORD end;
DWORD runtime;
DWORD LocalFileSize; runtime = ;
start = timeGetTime(); //读取本地文件大小
if (CFile::GetStatus(strSavePath, fileStatus))
{
LocalFileSize = fileStatus.m_size;
}
//解析URL字符串并返回服务的类型及组件
AfxParseURL(downloadedUrl, dw, strServer, strObject, nPort);
//判断是否是HTTP服务器
if (dw != AFX_INET_SERVICE_HTTP && dw != AFX_INET_SERVICE_HTTPS)
{
m_ErrorInfo.m_dwError = ;
m_ErrorInfo.m_strErrorMsg = (CString)downloadedUrl + L"网址不是http类型服务器";
ErrorNotifyObserver(&m_ErrorInfo);
return FALSE;
}
try{
m_HttpConnection = m_InternetSession->GetHttpConnection(strServer,
dw == AFX_INET_SERVICE_HTTP ? INTERNET_FLAG_KEEP_CONNECTION : (INTERNET_FLAG_KEEP_CONNECTION | INTERNET_FLAG_SECURE),
nPort);
//二进制存储HTTP下载文件,阻止从缓存中加载文件
m_HttpFile = m_HttpConnection->OpenRequest(_T("GET"), strObject,
NULL, , NULL, NULL,
INTERNET_FLAG_RELOAD | INTERNET_FLAG_TRANSFER_BINARY |
(dw == AFX_INET_SERVICE_HTTP ? INTERNET_FLAG_KEEP_CONNECTION : (INTERNET_FLAG_KEEP_CONNECTION | INTERNET_FLAG_SECURE)));
//发送HTTP请求到指定的服务器。
m_HttpFile->SendRequest(NULL, , NULL, ); DWORD dwFileSize;
CString strFileSize;
CString strBegin;
strBegin.Format(TEXT("%d"), );
//获取文件大小
m_HttpFile->QueryInfo(HTTP_QUERY_CONTENT_LENGTH, dwFileSize);
m_HttpFile->QueryInfo(HTTP_QUERY_CONTENT_LENGTH, strFileSize);
if (dwFileSize != )
{
//对HTTP请求操作添加一个或多个请求头
m_HttpFile->AddRequestHeaders(_T("Range:") + strBegin + _T("-") + strFileSize + _T("\r\n"));
} CFile downloadedFile;
DWORD len;
if (m_overALL == true)
{
USES_CONVERSION;
remove(T2A(strSavePath));
}
//设置下载模式,不存在的话创建文件,存在的话不会清空这个文件
downloadedFile.Open(strSavePath, CFile::modeCreate | CFile::modeNoTruncate | CFile::modeWrite); // 设定每个数据包大小,通过这个调整下载速度,但是如果包特别大的话速度还是特别慢
CHAR szBuf[] = { };
DWORD dwSize = sizeof(szBuf); DWORD fileLength = downloadedFile.GetLength();
downloadedFile.SeekToEnd();
DWORD AllLength = dwFileSize; m_HttpFile->Seek(fileLength, CFile::begin);
ReadTransmisson(configFile);
m_Transmisson.m_httpFileSize = dwFileSize; //判断文件是否已经下载完成
if (LocalFileSize == dwFileSize)
{
if (m_overALL == false)
{
m_ErrorInfo.m_dwError = ;
m_ErrorInfo.m_strErrorMsg = (CString)downloadedUrl + L"文件已经下载";
ErrorNotifyObserver(&m_ErrorInfo);
downloadedFile.Close();
return false;
} }
if (m_Transmisson.m_downloadedFileSize == )
{
while ((len = m_HttpFile->Read(szBuf, dwSize)) > )
{
fileLength += len;
downloadedFile.Write(szBuf, len);
ZeroMemory(szBuf, sizeof(szBuf)); m_Transmisson.m_downloadSpeed = (fileLength * 100.0) / AllLength;
m_Transmisson.m_downloadAddress = downloadedUrl; float fSpeed = ;
fSpeed = (float)fileLength;
fSpeed /= (float)((float)runtime / (float));
m_Transmisson.m_downloadKB = fSpeed / (float); RecordTransmisson(downloadedUrl, configFile, dwFileSize, fileLength, m_Transmisson.m_downloadSpeed, runtime);
m_Transmisson.m_downloadedFileSize = fileLength;
m_Transmisson.m_runTime = runtime;
DownloadedNotifyObserver(&m_Transmisson); end = timeGetTime();
runtime = end - start;
if (runtime == )
{
runtime = ;
}
if (m_exit == false)
{
downloadedFile.Close();
clear();
break;
}
}
}
//文件已经存在,进行断点续传
else
{
if (m_Transmisson.m_downloadAddress!= downloadedUrl)
{
m_ErrorInfo.m_dwError = ;
m_ErrorInfo.m_strErrorMsg = (CString)strSavePath + L"文件下载地址错误";
ErrorNotifyObserver(&m_ErrorInfo);
downloadedFile.Close();
return false;
}
runtime= m_Transmisson.m_runTime+;
DWORD downloadedSize =m_Transmisson.m_downloadedFileSize;
while ((len = m_HttpFile->Read(szBuf, dwSize)) > )
{
double speed = m_Transmisson.m_downloadSpeed;
downloadedSize += len;
fileLength += len;
downloadedFile.Write(szBuf, len);
ZeroMemory(szBuf, sizeof(szBuf));
m_Transmisson.m_downloadSpeed = (fileLength * 100.0) / AllLength;
m_Transmisson.m_downloadedFileSize=fileLength; float fSpeed = ;
fSpeed = (float)fileLength;
fSpeed /= (float)((float)runtime / (float));
m_Transmisson.m_downloadKB = fSpeed / (float); //存储下载文件大小
RecordTransmisson(downloadedUrl, configFile, dwFileSize, (int)fileLength, m_Transmisson.m_downloadSpeed, runtime);
DownloadedNotifyObserver(&m_Transmisson); end = timeGetTime() + m_Transmisson.m_runTime;
runtime = end - start;
if (runtime == )
{
runtime = ;
} if (m_exit == false)
{
downloadedFile.Close();
clear();
break;
}
}
}
downloadedFile.Close();
}
catch (CInternetException *e)
{
m_ErrorInfo.m_dwError = e->m_dwError;
TCHAR szErrorMsg[] = { };
e->GetErrorMessage(szErrorMsg, );
m_ErrorInfo.m_strErrorMsg = szErrorMsg ;
ErrorNotifyObserver(&m_ErrorInfo);
e->Delete();
return FALSE;
}
return TRUE;
}
文件存储
void CHttpDownLoader::RecordTransmisson(LPCTSTR downloadedUrl, LPCTSTR configFile, DWORD downloadFileSize, DWORD readedLenght, double downloadedSpeed, DWORD runTime)
{
USES_CONVERSION;
string downloadAddress W2A(downloadedUrl); ofstream in;
in.open(configFile, ios::trunc);
if (!in.is_open())
{
m_ErrorInfo.m_dwError = ;
m_ErrorInfo.m_strErrorMsg = (CString)downloadedUrl + L"文件无法打开";
ErrorNotifyObserver(&m_ErrorInfo);
//没有成功的执行一个程序
}
in.clear();
Document document;
Document::AllocatorType& allocator = document.GetAllocator();
Value root(kObjectType); root.AddMember("DownloadedAddress", StringRef(downloadAddress.c_str()), allocator);
root.AddMember("FileSize", (uint64_t)downloadFileSize, allocator);
root.AddMember("DownLoadSize", (uint64_t)readedLenght, allocator);
root.AddMember("DownLoadPercentage", downloadedSpeed, allocator);
root.AddMember("RunTime", (uint64_t)runTime, allocator); StringBuffer buffer;
Writer<StringBuffer> writer(buffer);
root.Accept(writer);
std::string result = buffer.GetString();
in << result;
in.close();
} void CHttpDownLoader::ReadTransmisson(LPCTSTR configFile)
{
USES_CONVERSION;
FILE *config = fopen(T2A(configFile), "a");
//移动指针到文件末尾
fseek(config, , SEEK_END);
//判断文件是否为空
if (ftell(config) == )
{
fclose(config);
m_Transmisson.m_httpFileSize = ;
m_Transmisson.m_downloadedFileSize = ;
m_Transmisson.m_downloadSpeed = ;
m_Transmisson.m_runTime = ;
configFile = NULL;
return ;
}
else
{
fclose(config);
Document doc;
ifstream ifs(T2A(configFile), ios_base::binary);
string str;
std::copy(std::istream_iterator<unsigned char>(ifs), std::istream_iterator<unsigned char>(), back_inserter(str));
doc.Parse<>(str.c_str());
Value & dress = doc["DownloadedAddress"];
Value & fileSize = doc["FileSize"];
Value & DownLoadedSize = doc["DownLoadSize"];
Value & downloadSpeed = doc["DownLoadPercentage"];
Value & runTime = doc["RunTime"]; m_Transmisson.m_downloadAddress = dress.GetString();
m_Transmisson.m_httpFileSize = fileSize.GetInt();
m_Transmisson.m_downloadedFileSize = DownLoadedSize.GetInt();
m_Transmisson.m_downloadSpeed = downloadSpeed.GetDouble();
m_Transmisson.m_runTime = runTime.GetFloat();
}
configFile = NULL;
return ;
}
观察者模式
HttpDownLoaded.h class IDownloadObserver
{
public:
//更新下载信息
virtual void UpdateDownloadInfo(CString m_downloadAddress, double speed, DWORD m_httpfileSize, DWORD m_downloadedFileSize, int m_downloadKB, DWORD runTime) = ;
//更新错误信息
virtual void UpdateErrorMsg(DWORD errorID, CString strErrorMsg) = ;
}; class CHttpDownLoader
{
public:
CHttpDownLoader();
virtual ~CHttpDownLoader();
public:
struct Transmisson
{
//下载地址
CString m_downloadAddress;
//文件大小
DWORD m_httpFileSize;
//已下载大小
DWORD m_downloadedFileSize;
//下载百分比
double m_downloadSpeed; int m_downloadKB; DWORD m_runTime; } m_Transmisson; struct ErrorInfo
{
DWORD m_dwError;
CString m_strErrorMsg;
}m_ErrorInfo;
//建立观察者
void SetObserver(IDownloadObserver * pObserver);
//更新下载速度数据
void DownloadedNotifyObserver(Transmisson *pTransmisson);
//更新错误信息数据
void ErrorNotifyObserver(ErrorInfo *m_ErrorInfo);
}
HttpDownLoadDlg.h class CHttpDownLoadDlg : public CDialogEx, public IDownloadObserver
{
// 构造
public:
CHttpDownLoadDlg(CWnd* pParent = NULL); // 标准构造函数 // 对话框数据
enum { IDD = IDD_HTTPDOWNLOAD_DIALOG }; protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 // 实现
protected:
void UpdateDownloadInfo(CString m_downloadAddress, double speed, DWORD m_httpfileSize, DWORD m_downloadedFileSize, int downloadKB, DWORD runTime);
void UpdateErrorMsg(DWORD errorID, CString strErrorMsg);
};
#include "HttpDownLoaded.h" void CHttpDownLoader::SetObserver(IDownloadObserver * pObserver)
{
m_downloadTransmissonVectors.push_back(pObserver);
m_errorMsgVectors.push_back(pObserver);
} void CHttpDownLoader::DownloadedNotifyObserver(Transmisson *pTransmisson)
{
MSG msg;
for (auto it = m_downloadTransmissonVectors.begin(); it != m_downloadTransmissonVectors.end(); it++)
{
(*it)->UpdateDownloadInfo(pTransmisson->m_downloadAddress, pTransmisson->m_downloadSpeed, pTransmisson->m_httpFileSize, pTransmisson->m_downloadedFileSize, pTransmisson->m_downloadKB, pTransmisson->m_runTime); if (PeekMessage(&msg, NULL, , , PM_REMOVE))
{
if (msg.message == WM_QUIT)
{
ExitProcess();
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
} void CHttpDownLoader::ErrorNotifyObserver(ErrorInfo *m_ErrorInfo)
{
for (auto it = m_errorMsgVectors.begin(); it != m_errorMsgVectors.end(); it++)
{
(*it)->UpdateErrorMsg(m_ErrorInfo->m_dwError, m_ErrorInfo->m_strErrorMsg);
}
}
#include "HttpDownLoadDlg.h" void CHttpDownLoadDlg::UpdateDownloadInfo(CString m_downloadAddress, double speed, DWORD m_httpfileSize, DWORD m_downloadedFileSize, int downloadKB, DWORD runTime)
{
m_progress.SetPos((int)speed);
CString strPercent, KBsec;
strPercent.Format(L"%d%%", (int)speed);
KBsec.Format(L"%d KB/秒", downloadKB);
SetDlgItemText(IDC_PERCENT_TEXT, strPercent);
SetDlgItemText(IDC_SPEED, KBsec);
if (m_downloadedFileSize == m_httpfileSize)
{
CFile tempFile;
tempFile.Remove(L"E:\\recod.config");
MessageBox(L"文件下载完成!", L"OK", MB_ICONINFORMATION);
exit(EXIT_SUCCESS);
} } void CHttpDownLoadDlg::UpdateErrorMsg(DWORD errorID, CString strErrorMsg)
{ }
Http协议的断点续传下载器,使用观察者模式监视下载进度,使用xml保存下载进度。的更多相关文章
- IDM下载器使用方法详解:百度网盘下载,视频会员一网打尽!
一. IDM的设置 [01]IDM插件与各大浏览器的集成 默认情况下,在成功安装IDM后,直接点击这里的选项,会弹出[常规设置],一般情况下直接保持默认的配置即可,如果你使用的是比较小众的浏览器,你可 ...
- 我的Android进阶之旅------>Android基于HTTP协议的多线程断点下载器的实现
一.首先写这篇文章之前,要了解实现该Android多线程断点下载器的几个知识点 1.多线程下载的原理,如下图所示 注意:由于Android移动设备和PC机的处理器还是不能相比,所以开辟的子线程建议不要 ...
- 在firefox的flashgot中配置各种下载器
一.在firefox中安装flashgot下载管理器 flashgot是firefox的一个扩展,在联网的情况下,可以在firefox中的附加组件中搜索flashgot,然后安装. 二.在flashg ...
- 基于iOS 10、realm封装的下载器
代码地址如下:http://www.demodashi.com/demo/11653.html 概要 在决定自己封装一个下载器前,我本以为没有那么复杂,可在实际开发过程中困难重重,再加上iOS10和X ...
- 第5章 网页下载器和urllib2模块
网页下载器:将互联网上URL对应的网页下载到本地的工具 通过网页下载器将互联网中的url网页,存储到本地或内存字符串 python有哪几种网页下载器? 1.urllib2 python官方基础模块 ...
- 单片机入门学习笔记5:STC下载器
STC下载器主要集成了, 1.芯片识别,下载/编程 2.端口识别 3.串口助手 4.KEIL仿真设置 5.芯片选型 6.范例程序 (集成了定时器,串口等例程) 7.波特率计算器 8.定时器计算器 9. ...
- 网页站点下载器teleport ultra
软件名称:teleport ultra 介绍:teleport ultra是一款专门的网页站点下载器,使用这款工具可以方便地下载网页数据,包括网站的文字.图片.flash动画等,可以轻松下载所有的网站 ...
- Scrapy入门到放弃04:下载器中间件,让爬虫更完美
前言 MiddleWare,顾名思义,中间件.主要处理请求(例如添加代理IP.添加请求头等)和处理响应 本篇文章主要讲述下载器中间件的概念,以及如何使用中间件和自定义中间件. MiddleWare分类 ...
- Android开发多线程断点续传下载器
使用多线程断点续传下载器在下载的时候多个线程并发可以占用服务器端更多资源,从而加快下载速度,在下载过程中记录每个线程已拷贝数据的数量,如果下载中断,比如无信号断线.电量不足等情况下,这就需要使用到断点 ...
随机推荐
- Cocos2d-x第三方类库不支持arm64的问题解决(64位架构)
32位能够兼容64位操作系统. ipad mini2 64位编译有问题. 各种第三方库不支持64位操作系统. 设置build setting 直接上图:
- rgba
正反两面展示效果 <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head& ...
- .Net中字典的使用
/// <summary> /// 获取用户市信息 /// </summary> /// <param name="CustomerId">&l ...
- 分布式架构中shiro
分布式架构中shiro 前言:前段时间在搭建公司游戏框架安全验证的时候,就想到之前web最火的shiro框架,虽然后面实践发现在netty中不太适用,最后自己模仿shiro写了一个缩减版的,但是中间花 ...
- 12.ng-switch
转自:https://www.cnblogs.com/best/tag/Angular/ 根据作用域表达式动态切换把那个DOM元素包含在已经编译的模板中. 示例代码: <!DOCTYPE htm ...
- 2.CString转换到char*
多字节模式下: CString -->char * CString str1 ="; char *t1 =str1.GetBuffer(str1.GetLength()); str1. ...
- Gym - 100637B Lunch 规律
题意:n个点,给定起点和终点,可以每次可以走一格或两格,走一格则需要一个代价,每个格子只能走一次,问从起点到终点并经过每一个点的最小代价 思路:这题我没看出什么道理,先打了个暴力,结果发现了个相当坑的 ...
- 最长回文子串 hihocode 1032 hdu 3068
最长回文 Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submi ...
- 原型,构造函数,实例,__proto__
再说说__proto__,这个孩子性格慢向,所以即使在现代浏览器广为支持得今天也不建议使用,性能特别慢,而且影响所有来自该[[prototype]]的对象.只是拿出来了解了解: 1.它是个啥? 原型对 ...
- linux安装lrzsz支持rz从windows上传文件到linux
1.下载lrzsz wget https://wangxuejin-data-1252194948.cos.ap-shanghai.myqcloud.com/lrzsz-0.12.20.tar.gz ...