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开发多线程断点续传下载器
使用多线程断点续传下载器在下载的时候多个线程并发可以占用服务器端更多资源,从而加快下载速度,在下载过程中记录每个线程已拷贝数据的数量,如果下载中断,比如无信号断线.电量不足等情况下,这就需要使用到断点 ...
随机推荐
- url与图片
http://restapi.amap.com/v3/staticmap?location=116.481485,39.990464&zoom=10&size=750*300& ...
- lightoj--1116--Ekka Dokka(水题)
Ekka Dokka Time Limit: 2000MS Memory Limit: 32768KB 64bit IO Format: %lld & %llu Submit Stat ...
- Redis封装值ZSet
/// <summary> /// Sorted Sets是将 Set 中的元素增加了一个权重参数 score,使得集合中的元素能够按 score 进行有序排列 /// 1.带有权重的元素 ...
- Linux桌面词典 星际译王(StarDict)
星际译王(StarDict)是利用GTK(GIMP TOOLKIT)开发的国际化的.跨平台的自由的桌面字典软件.它并不包含字典档,使用者须自行下载配合使用.它可以运行于多种不同的平台,如Linux, ...
- 联想 Thinkserver TS250服务器RAID1 重建测试
1.RAID1状态下,拨掉其中一块硬盘后,RAID1即失效. 2.重新插入后,在进行系统后会自动重建 *RAID1 提示Rebuild *进入桌面后软件,显示重建进度 软件下载地址:https://p ...
- JS的解析与执行过程—全局预处理阶段之命名冲突的处理策略
有如下代码: <body> <script> alert(f); function f() { console.log("fff"); } var f = ...
- 【Uva 1625】Color Length
[Link]: [Description] 给你两个序列,都由大写字母组成; 每次,把两个序列中的一个的开头字母加在字符串的尾端,然后在那个序列中删掉那个开头字母; 最后得到一个字符串; 这个字符串显 ...
- UVA 11642 Fire!
Fire! Time Limit: 1000ms Memory Limit: 131072KB This problem will be judged on UVA. Original ID: 116 ...
- [Javascript] this in Function Calls
In most cases, the value of a function's this argument is determined by how the function is called. ...
- Ubuntu中的解压缩文件的方式
记录Ubuntu下各种压缩和解压方式: .tar 解包:tar xvf FileName.tar 打包:tar cvf FileName.tar DirName (注:tar是打包,不是压缩!) -- ...