昨天使用了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 printf("=");}for ( ; 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
不同的版本,不同的处理:
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);/* xferinfo was introduced in 7.32.0, no earlier libcurl versions willcompile 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 newcallback, making the older callback get used.New libcurls will prefer the new callback and instead use that one evenif both callbacks are set. */ curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, xferinfo);/* pass the struct pointer into the xferinfo function, note that this isan alias to CURLOPT_PROGRESSDATA */ curl_easy_setopt(curl, CURLOPT_XFERINFODATA, &prog);
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;
}