zoukankan      html  css  js  c++  java
  • 使用libcurl来下载文件

    /*!
    * Email: scictor@gmail.com
    * Auth:  scictor
    * Date:  6/9/2020
    * File:  DownloaderMainT.cpp
    * Class: %{Cpp:License:ClassName} (if applicable)
    * variable:
    * Brief:
    * Note:
     */
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <curl/curl.h>
    #include "Downloader.h"
    
    #pragma comment(lib,"libcurl.lib")
    
    int _tmain(int argc, char* argv[])
    {
        DWORD tick = GetTickCount();
        CDownloader murl;
         DLIO mDlWork;
    
        strcpy(mDlWork.url, "http://sw.bos.baidu.com/sw-search-sp/software/f69ab46476e8e/TGPSetup_2.3.2.4083.exe");
        strcpy(mDlWork.filePath, ".\DownloadSoft\");
        murl.AddDownloadWork(mDlWork);      //添加到下载任务中
    
        strcpy(mDlWork.url, "http://sw.bos.baidu.com/sw-search-sp/software/16f6d358815f2/iTunes_12.5.1.21.exe");
        strcpy(mDlWork.filePath, ".\DownloadSoft\");
        murl.AddDownloadWork(mDlWork);      //添加到下载任务中
    
        murl.StartDownloadThread();         //开启下载线程
        CURDI curInfo;
        double curDownloadLen,preLen = 0.0;
        while(1)
        {
            if(murl.IsDownloadBegin())
            {
                murl.GetCurrentDownloadInfo(&curInfo);       //获取每次下载的信息(一次相当于毫秒级,这里速度也用毫秒计算)
                curDownloadLen = curInfo.CurDownloadLen;
                printf("正在下载:%s,下载进度:%6.2lf%%,下载速度:%9.2lfKB/s
    ",curInfo.fileName,
                    ((double)curInfo.preLocalLen+curInfo.CurDownloadLen)/curInfo.totalFileLen*100,(curDownloadLen-preLen)/(double)(GetTickCount()-tick));
                tick = GetTickCount();
                Sleep(500);
            }
            if(murl.IsDownloadEnd()) break;
            preLen = curDownloadLen;
        }
        return 0;
    }
    /*!
    * Email: scictor@gmail.com
    * Auth:  scictor
    * Date:  6/9/2020
    * File:  Downloader.cpp
    * Class: Downloader (if applicable)
    * variable:
    * Brief:
    * Note:
     */
    
    #include "Downloader.h"
    //#include <io.h>
    
    CDownloader::CDownloader(void)
    {
        m_downloadCourse = -1;
        m_nConnectTimeOut = 0;
        curl_global_init (CURL_GLOBAL_ALL);
        for(int i=0; i<MAXWORK; i++)
        {
            memset(m_dowloadWork->url, 0, 512);
            memset(m_dowloadWork->filePath, 0, 256);
        }
        m_curIndex = 0;
    }
    
    
    CDownloader::~CDownloader(void)
    {
        curl_global_cleanup();
    }
    
    bool CDownloader::IsDownloadBegin()
    {
        if(m_downloadCourse == 0)
            return true;
        return false;
    }
    
    bool CDownloader::IsDownloadEnd()
    {
        if(m_downloadCourse == 1)
            return true;
        return false;
    }
    
    bool CDownloader::CreateMultiDir(const char* pathName)
    {
        if(pathName == NULL) return false;
        char filePath[256] = {0};
        strcpy(filePath, pathName);
        int i = 0, pathLen = strlen(pathName);
        CString curPath;
        char curFilePath[256] = {0};
        WIN32_FIND_DATA swf;
        if(filePath[pathLen - 1] != '\')    //最后一个非0字符不是‘\’则加上
        {
            filePath[pathLen] = '\';
        }
        while(filePath[i] != '')
        {
            if(filePath[i] == ':')
            {
                i+=2;
                continue;
            }
            if(filePath[i] == '\')
            {
                memcpy(curFilePath, filePath, i);
                curFilePath[i] = '';
                curPath = curFilePath;
                if(FindFirstFile(curPath, &swf) == INVALID_HANDLE_VALUE) //目录不存在就创建
                {
                    if(!CreateDirectory(curPath, NULL))
                    {
                        return false;
                    }
                }
            }
            i++;
        }
        return true;
    }
    
    void CDownloader::AddDownloadWork(DLIO downloadWork)
    {
        char filePath[256] = {0};
        char mUrl[512] = {0};
        strcpy(mUrl, downloadWork.url);
        strcpy(filePath, downloadWork.filePath);
        int i = strlen(filePath) -1;
        bool isPath = true;
        while(filePath[i] != '\')
        {
            if(filePath[i] == '.' && filePath[i+1] != '')
            {
                isPath = false;
            }
            i--;
        }
        if(isPath)
        {
            if(!CreateMultiDir(filePath))
                return;
            char fileName[256] = {0};
            GetFileNameFormUrl(fileName,mUrl);
            if(filePath[strlen(filePath)-1] != '\')
            {
                strcat(filePath, "\");
            }
            strcat(filePath, fileName);
        }
        else
        {
            char realPath[256] = {0};
            for(int k=0; k<i; k++)
            {
                realPath[k] = filePath[k];
            }
            realPath[i] = '\';
            if(!CreateMultiDir(realPath))
                return;
        }
        strcpy(m_dowloadWork[m_curIndex].url, mUrl);
        strcpy(m_dowloadWork[m_curIndex].filePath, filePath);
        m_curIndex++;
    }
    
    void CDownloader::GetFileNameFormUrl(char* fileName, const char* url)
    {
        int urlLen = strlen(url);
        char mUrl[512] = {0};
        char fName[256] = {0};
        strcpy(mUrl, url);
        int cutIndex = 0;
        int i = urlLen - 1, j = 0;
        while(mUrl[--i] != '/');
        i++;
        while(mUrl[i] != '' && mUrl[i] != '?' &&mUrl[i] != '&')
        {
            fName[j++] = mUrl[i++];
        }
        fName[j] = '';
        strcpy(fileName, fName);
        return ;
    }
    
    long CDownloader::GetLocalFileLenth(const char* fileName)
    {
        if(m_downloadCourse == 0)        //文件已经开始下载的时候,取到的是下载前本地文件的大小;
            return m_curLocalFileLenth;
        char strTemp[256] = {0};
        strcpy(strTemp,fileName);
        FILE* fp = fopen(strTemp, "rb");
        if(fp != NULL)
        {
            m_curLocalFileLenth = filelength(fileno(fp));
            fclose(fp);
            return m_curLocalFileLenth;
        }
        return 0;
    }
    
    double CDownloader::GetTotalFileLenth(const char* url)
    {
        char mUrl[512] = {0};
        strcpy(mUrl, url);
        double downloadFileLenth = 0;
        CURL* pCurl = curl_easy_init();
        curl_easy_setopt(pCurl, CURLOPT_URL, mUrl);
        curl_easy_setopt(pCurl, CURLOPT_HEADER, 1L);
        curl_easy_setopt(pCurl, CURLOPT_NOBODY, 1L);
        if(curl_easy_perform(pCurl) == CURLE_OK)
        {
            curl_easy_getinfo(pCurl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &downloadFileLenth);
        }
        else
        {
            downloadFileLenth = -1;
        }
        curl_easy_cleanup(pCurl);
        return downloadFileLenth;
    }
    
    
    size_t CDownloader::WriteFunc(char *str, size_t size, size_t nmemb, void *stream)
    {
        return fwrite(str, size, nmemb, (FILE*)stream);
    }
    
    size_t CDownloader::ProgressFunc(
        double* pFileLen,
        double t,// 下载时总大小
        double d, // 已经下载大小
        double ultotal, // 上传是总大小
        double ulnow)   // 已经上传大小
    {
        if(t == 0) return 0;
        *pFileLen = d;
        return 0;
    }
    
    int CDownloader::StartDownloadThread()
    {
        if(m_downloadCourse == -1||m_downloadCourse == 1)
        {
            HANDLE downloadThread = CreateThread(NULL, 0, SingleDownloadProc, this, 0, NULL);
            CloseHandle(downloadThread);
            return 0;
        }
        return -1;
    }
    
    DWORD WINAPI CDownloader::SingleDownloadProc(LPVOID lpParameter)
    {
        CDownloader* pDownload = (CDownloader*)lpParameter;
        int curDLIndex = 0;
        CURL* pCurl = curl_easy_init();
        while(curDLIndex <= pDownload->m_curIndex)
        {
            char fileName[256] = {0};
            char url[512] = {0};
            strcpy(fileName, pDownload->m_dowloadWork[curDLIndex].filePath);
            strcpy(url, pDownload->m_dowloadWork[curDLIndex].url);
            strcpy(pDownload->m_curDownloadInfo.url, url);
            strcpy(pDownload->m_curDownloadInfo.fileName, fileName);
            long localFileLen = pDownload->GetLocalFileLenth(fileName);
            pDownload->m_curLocalFileLenth = localFileLen;
            pDownload->m_curDownloadInfo.preLocalLen = pDownload->m_curLocalFileLenth;
            double totalFileLen = pDownload->m_curDownloadInfo.totalFileLen = pDownload->GetTotalFileLenth(url);
            if(localFileLen >= (long)totalFileLen)        //如果需要下载文件的大小大于等于本地文件的大小,直接下载下一个文件
            {
                curDLIndex++;
                pDownload->m_downloadCourse = -1;
                continue;
            }
            FILE* fp = fopen(fileName,"ab+");
            if(fp == NULL) //文件打开错误,进行下一个文件的下载
            {
                pDownload->m_downloadCourse = -1;
                continue;
            }
            curl_easy_setopt(pCurl, CURLOPT_URL, url);
            curl_easy_setopt(pCurl, CURLOPT_TIMEOUT, pDownload->m_nConnectTimeOut);
            curl_easy_setopt(pCurl, CURLOPT_HEADER, 0L);
            curl_easy_setopt(pCurl, CURLOPT_NOBODY, 0L);
            curl_easy_setopt(pCurl, CURLOPT_FOLLOWLOCATION, 1L);
            curl_easy_setopt(pCurl, CURLOPT_RESUME_FROM, localFileLen);
    
            curl_easy_setopt(pCurl, CURLOPT_WRITEFUNCTION, WriteFunc);
            curl_easy_setopt(pCurl, CURLOPT_WRITEDATA, fp);
    
            curl_easy_setopt(pCurl, CURLOPT_NOPROGRESS, 0L);
            curl_easy_setopt(pCurl, CURLOPT_PROGRESSFUNCTION, ProgressFunc);
            curl_easy_setopt(pCurl, CURLOPT_PROGRESSDATA, &(pDownload->m_curDownloadInfo.CurDownloadLen));
    
            pDownload->m_downloadCourse = 0;
            if(!curl_easy_perform(pCurl))
            {
                curDLIndex++;
                pDownload->m_downloadCourse = -1;
            }
            fclose(fp);
        }
        curl_easy_cleanup(pCurl);
        pDownload->m_downloadCourse = 1;
        return 0;
    }
    
    int CDownloader::GetCurrentDownloadInfo(CURDI* lpCurDownloadInfor)
    {
        *lpCurDownloadInfor = m_curDownloadInfo;
        return 0;
    }
    
    int CDownloader::SetConnectTimeOut(DWORD nConnectTimeOut)
    {
        if(m_downloadCourse == 0) return -1;
        else
            m_nConnectTimeOut = nConnectTimeOut;
        return 0;
    }
    /*!
    * Email: scictor@gmail.com
    * Auth:  scictor
    * Date:  6/9/2020
    * File:  Downloader.h
    * Class: Downloader (if applicable)
    * variable:
    * Brief:
    * Note:
     */
    
    
    
    #ifndef DOWNLOADER_H
    #define DOWNLOADER_H
    
    #include <stdio.h>
    #include <string.h>
    #include <curl/curl.h>
    //#include <atlstr.h>
    
    #define MAXWORK 200
    typedef struct DownloadInfo
    {
        char url[512];
        char filePath[256];
    }DLIO;
    
    typedef struct CurDownloadInfor
    {
        char url[512];     //url
        char fileName[256];   //文件名称
        long preLocalLen;     //本地已下载的长度(大小)
        double totalFileLen;   //文件总长度(大小)
        double CurDownloadLen;   //每次下载的文件长度(大小)
    }CURDI;
    
    class CDownloader
    {
    public:
        CDownloader(void);
        ~CDownloader(void);
        int StartDownloadThread();
        double GetTotalFileLenth(const char* url);             //获取将要下载的文件长度
        long GetLocalFileLenth(const char* fileName);         //获取本地问价长度
        void GetFileNameFormUrl(char* fileName, const char* url);      //从URL中获取文件名
        void AddDownloadWork(DLIO downloadWork);
        int SetConnectTimeOut(DWORD nConnectTimeOut);    //设置连接的超时时间
        int GetCurrentDownloadInfo(CURDI* lpCurDownloadInfor);
        bool CreateMultiDir(const char* pathName);       //是否在本地创建目录,没有就创建
        bool IsDownloadBegin();
        bool IsDownloadEnd();
    protected:
        static DWORD SingleDownloadProc(LPVOID lpParameter);       //线程函数
        static size_t WriteFunc(char *str, size_t size, size_t nmemb, void *stream);     //写入数据(回调函数)
        static size_t ProgressFunc(double* fileLen, double t, double d, double ultotal, double ulnow);   //下载进度
    private:
        char m_filePath[512];
        char m_downloadUrl[256];
        int m_downloadCourse;   //-1 还未下载 0正在下载 1下载完成
        long m_curLocalFileLenth; //因为下载的时候已经计算了本地文件的大小用来设置断点,所以对于每个文件,该数字只会被设置一次;就是下载前的本地大小;
        long m_nConnectTimeOut;      //连接的超时时间
        DLIO m_dowloadWork[MAXWORK];
        CURDI m_curDownloadInfo;
        int m_curIndex;
        CURL* m_pCurl;
    };
    
    
    //https://blog.csdn.net/qq_25867649/java/article/details/52789467
    
    #endif // DOWNLOADER_H
  • 相关阅读:
    FTP Protocol
    File Operations
    Ubuntu Install Chinese Input Method
    Vim Intro
    ISA Introduction
    Fourier Transform
    Process/Thread Synchronization
    Process Synchronization-Example 2
    leetcode 栈和队列类型题
    leetcode 字符串类型题
  • 原文地址:https://www.cnblogs.com/guxuanqing/p/12006769.html
Copyright © 2011-2022 走看看