下载使用Http协议,为了做到断点续传,在点击暂停后,将已下载的大小等数据通过Json存入xml中,当继续传输的时候从xml文件中读取大小继续下载(好几个月前写的,真的想不起来了)
bool CHttpDownLoader::DownLoadData(LPCTSTR downloadedUrl, LPCTSTR strSavePath, LPCTSTR configFile) { m_InternetSession = new CInternetSession(HTTPINFO, 1, 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 = 10; 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 = 0; 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, 1, 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, 0, NULL, 0); DWORD dwFileSize; CString strFileSize; CString strBegin; strBegin.Format(TEXT("%d"), 0); //获取文件大小 m_HttpFile->QueryInfo(HTTP_QUERY_CONTENT_LENGTH, dwFileSize); m_HttpFile->QueryInfo(HTTP_QUERY_CONTENT_LENGTH, strFileSize); if (dwFileSize != 0) { //对HTTP请求操作添加一个或多个请求头 m_HttpFile->AddRequestHeaders(_T("Range:") + strBegin + _T("-") + strFileSize + _T(" ")); } CFile downloadedFile; DWORD len; if (m_overALL == true) { USES_CONVERSION; remove(T2A(strSavePath)); } //设置下载模式,不存在的话创建文件,存在的话不会清空这个文件 downloadedFile.Open(strSavePath, CFile::modeCreate | CFile::modeNoTruncate | CFile::modeWrite); // 设定每个数据包大小,通过这个调整下载速度,但是如果包特别大的话速度还是特别慢
CHAR szBuf[800] = { 0 }; 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 = 0; m_ErrorInfo.m_strErrorMsg = (CString)downloadedUrl + L"文件已经下载"; ErrorNotifyObserver(&m_ErrorInfo); downloadedFile.Close(); return false; } } if (m_Transmisson.m_downloadedFileSize == 0) { while ((len = m_HttpFile->Read(szBuf, dwSize)) > 0) { 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 = 0; fSpeed = (float)fileLength; fSpeed /= (float)((float)runtime / (float)1000); m_Transmisson.m_downloadKB = fSpeed / (float)1024; 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 == 0) { runtime = 10; } if (m_exit == false) { downloadedFile.Close(); clear(); break; } } } //文件已经存在,进行断点续传 else { if (m_Transmisson.m_downloadAddress!= downloadedUrl) { m_ErrorInfo.m_dwError = 0; m_ErrorInfo.m_strErrorMsg = (CString)strSavePath + L"文件下载地址错误"; ErrorNotifyObserver(&m_ErrorInfo); downloadedFile.Close(); return false; } runtime= m_Transmisson.m_runTime+10; DWORD downloadedSize =m_Transmisson.m_downloadedFileSize; while ((len = m_HttpFile->Read(szBuf, dwSize)) > 0) { 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 = 0; fSpeed = (float)fileLength; fSpeed /= (float)((float)runtime / (float)1000); m_Transmisson.m_downloadKB = fSpeed / (float)1024; //存储下载文件大小
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 == 0) { runtime = 10; } if (m_exit == false) { downloadedFile.Close(); clear(); break; } } } downloadedFile.Close(); } catch (CInternetException *e) { m_ErrorInfo.m_dwError = e->m_dwError; TCHAR szErrorMsg[255] = { 0 }; e->GetErrorMessage(szErrorMsg, 255); 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 = 0; 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, 0, SEEK_END); //判断文件是否为空 if (ftell(config) == 0) { fclose(config); m_Transmisson.m_httpFileSize = 0; m_Transmisson.m_downloadedFileSize = 0; m_Transmisson.m_downloadSpeed = 0; m_Transmisson.m_runTime = 0; 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<0>(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) = 0; //更新错误信息 virtual void UpdateErrorMsg(DWORD errorID, CString strErrorMsg) = 0; }; 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, 0, 0, PM_REMOVE)) { if (msg.message == WM_QUIT) { ExitProcess(0); } 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) { }