Http协议的断点续传下载器,使用观察者模式监视下载进度,使用xml保存下载进度。

下载使用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)
{

}

代码下载

原文地址:https://www.cnblogs.com/ye-ming/p/7838466.html