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;
}

 

 

posted @ 2014-04-16 13:06  haroel  阅读(570)  评论(0编辑  收藏  举报