zoukankan      html  css  js  c++  java
  • libcurl断点下载

    开发需要写了一个处理curl 下载的c++类,内含有多个静态方法和实例方法,写在这里留给有需求的同学

    头文件
    
    CURLHelper.h
    
    enum CURLHelperStateType
    {
        CURLHelper_START = 0,
        CURLHelper_PROGRESS = 1,
        CURLHelper_COMPLETE = 2,
        CURLHelper_UNKNOW = 99
    };
    
    class CURLHelper
    {
    public:
        static std::string getHttpString(const char * url);
    
        static long getDownloadFileSize(const char *url);
        
        static long getLocalFileSize(const char *localpath);
        
        
        CURLHelper();
        ~CURLHelper();
        
        void downloadFile(const char *url,const char *localpath);
        
        void downloadProgressCallback(double percent);
        
        long getTotalFileSize();
        
        CURLHelperStateType getState();
        
        double getPercent();
        
        void doDownload();
    private:
        string m_url;
        string m_local_path;
        
        double m_fileTotalSize;
    //    double m_currentFileSize;
        
        double m_percent;
        
        pthread_t *pDownloadThread;
    
        int reDownloadCount;
        CURLHelperStateType m_currentState;
    };
    /**
     *  获取服务器文件的字符 ,阻塞式
     *  @param url
     *  @return
     */
    string CURLHelper::getHttpString(const char *url)
    {
        std::string str = "";
        CURL *_curl = curl_easy_init();
        if (! _curl)
        {
            CCLOG("can not init curl");
            return str;
        }
        curl_easy_setopt(_curl, CURLOPT_URL, url);
        curl_easy_setopt(_curl, CURLOPT_SSL_VERIFYPEER, 0L);
        curl_easy_setopt(_curl, CURLOPT_WRITEFUNCTION, getCharCode);
        curl_easy_setopt(_curl, CURLOPT_WRITEDATA, &str);
        
        CURLcode res = curl_easy_perform(_curl);
        if (res != CURLE_OK)
        {
            CCLOG("can not get version file content, error code is %d", res);
            curl_easy_cleanup(_curl);
            return str;
        }
        curl_easy_cleanup(_curl);
        return str;
    }
    /**
     *  获取服务器上的文件物理大小
     *  @param url
     *  @return
     */
    long CURLHelper::getDownloadFileSize(const char *url)
    {
        double downloadFileLenth = 0;
        CURL *handle = curl_easy_init();
        curl_easy_setopt(handle, CURLOPT_URL, url);
        curl_easy_setopt(handle, CURLOPT_HEADER, 1);    //只需要header头
        curl_easy_setopt(handle, CURLOPT_NOBODY, 1);    //不需要body
        if (curl_easy_perform(handle) == CURLE_OK)
        {
            curl_easy_getinfo(handle, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &downloadFileLenth);
        }
        else
        {
            downloadFileLenth = -1;
        }
        return downloadFileLenth;
    }
    /**
     *  获取本地文件大小
     *  @param localpath
     *  @return
     */
    long CURLHelper::getLocalFileSize(const char *localpath)
    {
        curl_off_t local_file_len = 0;
        struct stat file_info;
        if(stat(localpath, &file_info) == 0)
        {
            local_file_len =  file_info.st_size;
        }
        return local_file_len;
    }
    
    /* 保存下载文件 */
    
    size_t wirtefunc(void *ptr, size_t size, size_t nmemb, void *stream)
    {
        FILE *fp = (FILE*)stream;
        size_t written = fwrite(ptr, size, nmemb, fp);
        return written;
    }
    /* 下载回调的计算进度条的函数 */
    static int progress_func(void *ptr, double totalToDownload, double nowDownloaded, double totalToUpLoad, double nowUpLoaded)
    {
        CURLHelper *helper = (CURLHelper*)ptr;
        double curpercent = 100 * nowDownloaded / totalToDownload;
        
        helper->downloadProgressCallback(curpercent);
        return 0;
    }
    
    void CURLHelper::doDownload()
    {
        do
        {
            string tmpPath = m_local_path + ".tmp";
            FILE *localFile = NULL;
            
            double m_currentTmpSize = CURLHelper::getLocalFileSize(tmpPath.c_str());
            
            if (m_currentTmpSize > 0)
            {
                localFile = fopen(tmpPath.c_str(), "ab+");
                CCLOG("断点下载模式");
            }
            else
            {
                localFile = fopen(tmpPath.c_str(), "wb+");
            }
            int cc = error_no();
            if (!localFile)
            {
                break;
            }
            m_currentState = CURLHelper_PROGRESS;
            CURL *curlhandle = curl_easy_init();
            curl_easy_setopt(curlhandle, CURLOPT_URL, m_url.c_str());
    
            //写函数回调
            curl_easy_setopt(curlhandle, CURLOPT_WRITEDATA, localFile);
            curl_easy_setopt(curlhandle, CURLOPT_WRITEFUNCTION, wirtefunc);
            //断点下载
            curl_easy_setopt(curlhandle, CURLOPT_RESUME_FROM_LARGE, m_currentTmpSize);
            //下载进度回调
            curl_easy_setopt(curlhandle, CURLOPT_NOPROGRESS, 0L);
            curl_easy_setopt(curlhandle, CURLOPT_PROGRESSFUNCTION, progress_func);
            curl_easy_setopt(curlhandle, CURLOPT_PROGRESSDATA, this);
    
            CURLcode res = curl_easy_perform(curlhandle);
            fclose(localFile);
            curl_easy_cleanup(curlhandle);
    
            if (res == CURLE_OK)
            {
                //文件改名
                int result = rename(tmpPath.c_str(), m_local_path.c_str());
                int e = error_no();
                if (result == 0)
                {
                    CCLOG("改名成功");
                }
                else
                {
                    CCLOG("rename failed %d",e);
                }
            }
            else
            {
                CCLOG("下载失败,CURLcode %d",res);
                if (reDownloadCount < 3)
                {
                    //直接删除缓存文件
                    int removeCode = remove(tmpPath.c_str());
                    CCLOG("下载失败,删除tmp文件,并重新下载 %d",removeCode);
                    reDownloadCount++;
                    m_currentState = CURLHelper_START;
                    doDownload();
                    return;
                }
            }
    
        }
        while (0);
        m_currentState = CURLHelper_COMPLETE;
    }
    
    
    CURLHelper::CURLHelper()
    {
        m_currentState = CURLHelper_UNKNOW;
        pDownloadThread = NULL;
        m_percent = 0;
        reDownloadCount = 0;
    }
    
    CURLHelper::~CURLHelper()
    {
        CCLOG("~CURLHelper");
        if (pDownloadThread)
        {
            delete pDownloadThread;
        }
    }
    long CURLHelper::getTotalFileSize()
    {
        return m_fileTotalSize;
    }
    CURLHelperStateType CURLHelper::getState()
    {
        return m_currentState;
    }
    
    static void *thread_downloadFiles(void* data)
    {
        CURLHelper *helper = (CURLHelper*)data;
        helper->doDownload();
        return NULL;
    }
    
    void CURLHelper::downloadFile(const char *url, const char *localpath)
    {
        m_url = url;
        m_local_path = localpath;
        m_fileTotalSize = CURLHelper::getDownloadFileSize(url);
        m_percent = 0;
        //记录当前状态
        m_currentState = CURLHelper_START;
        //开启线程下载
        pDownloadThread = new pthread_t();
        pthread_create(&(*pDownloadThread), NULL, thread_downloadFiles, (void*)this);
    }
    void CURLHelper::downloadProgressCallback(double percent)
    {
        m_percent = percent;
    }
    double CURLHelper::getPercent()
    {
        return m_percent;
    }
  • 相关阅读:
    网站建设怎样添加设为首页和加入收藏代码
    在WEB项目中调用QQ通讯组件打开QQ聊天界面
    网页引用Font Awesome图标
    jQuery鼠标划入划出
    django框架
    python连接数据库:
    数据库:
    TCP:
    数据库:
    Excel在任务栏中只显示一个窗口的解决办法
  • 原文地址:https://www.cnblogs.com/howeho/p/3668389.html
Copyright © 2011-2022 走看看