libcurl--下载文件并实现进度条

昨天使用了windows api实现了下载文件以及显示下载进度:

Windows客户端开发–URLDownloadToFile下载文件进度条

今天就来说一使用libcurl实现http下载,并实现进度条。

简单介绍libcurl:
官网:
https://curl.haxx.se/
libcurl主要功能就是用不同的协议连接和沟通不同的服务器~也就是相当封装了的sockPHP 支持libcurl(允许你用不同的协议连接和沟通不同的服务器)。, libcurl当前支持http, https, ftp, gopher, telnet, dict, file, 和ldap 协议。libcurl同样支持HTTPS证书授权,HTTP POST, HTTP PUT, FTP 上传(当然你也可以使用PHP的ftp扩展), HTTP基本表单上传,代理,cookies,和用户认证。

使用libcurl:

文档:
https://curl.haxx.se/libcurl/c/libcurl-tutorial.html

For historical and traditional reasons, libcurl has a built-in progress meter that can be switched on and then makes it present a progress meter in your terminal.

Switch on the progress meter by, oddly enough, setting CURLOPT_NOPROGRESS to zero. This option is set to 1 by default.

For most applications however, the built-in progress meter is useless and what instead is interesting is the ability to specify a progress callback. The function pointer you pass to libcurl will then be called on irregular intervals with information about the current transfer.

Set the progress callback by using CURLOPT_PROGRESSFUNCTION. And pass a pointer to a function that matches this prototype:



 int progress_callback(void *clientp,
                       double dltotal,
                       double dlnow,
                       double ultotal,
                       double ulnow);

If any of the input arguments is unknown, a 0 will be passed. The first argument, the ‘clientp’ is the pointer you pass to libcurl with CURLOPT_PROGRESSDATA. libcurl won’t touch it.

开始:
根据上面的文档,实现我们自己的progress_func:

int progress_func(void* ptr, double TotalToDownload, double NowDownloaded, 
     double TotalToUpload, double NowUploaded)
{
 int totaldotz=40;
 double fractiondownloaded = NowDownloaded / TotalToDownload;

 int dotz = round(fractiondownloaded * totaldotz);

 int ii=0;
 printf("%3.0f%% [",fractiondownloaded*100);

 for ( ; ii < dotz;ii++) {
  printf("=");
 }

 for ( ; ii < totaldotz;ii++) {
  printf(" ");
 }

 printf("]\r");
 fflush(stdout);
}

同样根据文档:
setting CURLOPT_NOPROGRESS to zero
Set the progress callback by using CURLOPT_PROGRESSFUNCTION

FILE *file_param;
file_param = fopen("download_to_path", "wb");

curl_easy_setopt(curl, CURLOPT_WRITEDATA, file_param); 

curl_easy_setopt(curl, CURLOPT_NOPROGRESS, FALSE);

curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, progress_func)

最后看一个完整的官方例子:
https://curl.haxx.se/libcurl/c/progressfunc.html
不同的版本,不同的处理:

#include 
#include 

#define STOP_DOWNLOAD_AFTER_THIS_MANY_BYTES         6000
#define MINIMAL_PROGRESS_FUNCTIONALITY_INTERVAL     3

struct myprogress {
  double lastruntime;
  CURL *curl;
};

static int xferinfo(void *p,
                    curl_off_t dltotal, curl_off_t dlnow,
                    curl_off_t ultotal, curl_off_t ulnow)
{
  struct myprogress *myp = (struct myprogress *)p;
  CURL *curl = myp->curl;
  double curtime = 0;

  curl_easy_getinfo(curl, CURLINFO_TOTAL_TIME, &curtime);

  if((curtime - myp->lastruntime) >= MINIMAL_PROGRESS_FUNCTIONALITY_INTERVAL) {
    myp->lastruntime = curtime;
    fprintf(stderr, "TOTAL TIME: %f \r\n", curtime);
  }

  fprintf(stderr, "UP: %" CURL_FORMAT_CURL_OFF_T " of %" CURL_FORMAT_CURL_OFF_T
          "  DOWN: %" CURL_FORMAT_CURL_OFF_T " of %" CURL_FORMAT_CURL_OFF_T
          "\r\n",
          ulnow, ultotal, dlnow, dltotal);

  if(dlnow > STOP_DOWNLOAD_AFTER_THIS_MANY_BYTES)
    return 1;
  return 0;
}

/* for libcurl older than 7.32.0 (CURLOPT_PROGRESSFUNCTION) */ 
static int older_progress(void *p,
                          double dltotal, double dlnow,
                          double ultotal, double ulnow)
{
  return xferinfo(p,
                  (curl_off_t)dltotal,
                  (curl_off_t)dlnow,
                  (curl_off_t)ultotal,
                  (curl_off_t)ulnow);
}


int main(void)
{
  CURL *curl;
  CURLcode res = CURLE_OK;
  struct myprogress prog;

  curl = curl_easy_init();
  if(curl) {
    prog.lastruntime = 0;
    prog.curl = curl;

    curl_easy_setopt(curl, CURLOPT_URL, "http://example.com/");

    curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, older_progress);
    /* pass the struct pointer into the progress function */ 
    curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, &prog);

#if LIBCURL_VERSION_NUM >= 0x072000
    /* xferinfo was introduced in 7.32.0, no earlier libcurl versions will
       compile as they won't have the symbols around.

       If built with a newer libcurl, but running with an older libcurl:
       curl_easy_setopt() will fail in run-time trying to set the new
       callback, making the older callback get used.

       New libcurls will prefer the new callback and instead use that one even
       if both callbacks are set. */ 

    curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, xferinfo);
    /* pass the struct pointer into the xferinfo function, note that this is
       an alias to CURLOPT_PROGRESSDATA */ 
    curl_easy_setopt(curl, CURLOPT_XFERINFODATA, &prog);
#endif

    curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L);
    res = curl_easy_perform(curl);

    if(res != CURLE_OK)
      fprintf(stderr, "%s\n", curl_easy_strerror(res));

    /* always cleanup */ 
    curl_easy_cleanup(curl);
  }
  return (int)res;
}

你可能感兴趣的:(C++)