博客專欄

        EEPW首頁 > 博客 > libcurl:如何下載原始文件名的URL? (相當于“-O / – remote-name”)

        libcurl:如何下載原始文件名的URL? (相當于“-O / – remote-name”)

        發布人:電子禪石 時間:2020-09-29 來源:工程師 發布文章
        問題1:使用libcurl下載url時,如何保留下載文件的原始名稱? LibCurl要求程序員生成文件名.當URL具有時,這可能很容易
        例如在下面的url中,很容易找出目標名稱是 vimqrc.pdf.



        http://tnerual.eriogerg.free.fr/vimqrc.pdf)

        但是當URL動態生成目標名稱時,例如下載URL AdbeRdr1010_eu_ES.exe.使用wget(除URL之外沒有參數)和curl(參數-O)


        http://get.adobe.com/reader/download/?installer=Reader_10.1_Basque_for_Windows&standalone=1%22

        如何卷曲(-O)或wget計算出名稱


        //invoked as ./a.out <URL>#include <stdio.h>#include <curl/curl.h>char *location = "/tmp/test/out";size_t write_data(void *ptr, size_t size, size_t nmemb, FILE *stream) {
            size_t written = fwrite(ptr, size, nmemb, stream);    return written;
        }int main(int argc, char *argv[]){
            CURL        *curl;
            CURLcode    res;    int         ret = -1;    if (argc!= 2) {        //invoked as ./a.out <URL>
                return -1;
            } 
        
            curl = curl_easy_init();    if (!curl) {        goto bail;
            }
        
            FILE *fp = fopen(location, "wb");
            curl_easy_setopt(curl, CURLOPT_URL, argv[1]); //invoked as ./a.out <URL>
            /* example.com is redirected, so we tell libcurl to follow redirection */
            curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
            curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);    /* Perform the request, res will get the return code */
            res = curl_easy_perform(curl);    /* Check for errors */
            if(res != CURLE_OK)        fprintf(stderr, "curl_easy_perform() failed: %s\n",
                        curl_easy_strerror(res));    /* always cleanup */
            curl_easy_cleanup(curl);
            ret = 0;
            fclose(fp);
        
        bail:    return ret;
        }
        我在libcurl源代碼中找到了答案.看起來“遠程名稱”是標題中“content-disposition”標記的一部分. Libcurl正在解析標頭并在content-disposition標簽中查找“filename =”.此解析在通過CURLOPT_HEADERFUNCTION選項提供的回調中完成.最后,在寫入數據的回調中(通過CURLOPT_WRITEFUNCTION提供),此遠程名稱用于創建輸出文件.


        如果缺少文件名,它只是從URL本身中找出它.這是從lib curl復制的相當多的代碼,并且對我自己的修改很少,以使其更簡單并符合我的要求.


        #define _GNU_SOURCE #include <stdio.h>#include <curl/curl.h>#include <string.h>#include <sys/stat.h>#include <sys/types.h>#include <stdlib.h>typedef unsigned long uint64_t;typedef struct {    char        dnld_remote_fname[4096];    char        dnld_url[4096]; 
            FILE        *dnld_stream;
            FILE        *dbg_stream;
            uint64_t    dnld_file_sz;
        } dnld_params_t;static int get_oname_from_cd(char const*const cd, char *oname){    char    const*const cdtag   = "Content-disposition:";    char    const*const key     = "filename=";    int     ret                 = 0;    char    *val                = NULL;    /* Example Content-Disposition: filename=name1367; charset=funny; option=strange */
        
            /* If filename is present */
            val = strcasestr(cd, key);    if (!val) {        printf("No key-value for \"%s\" in \"%s\"", key, cdtag);        goto bail;
            }    /* Move to value */
            val += strlen(key);    /* Copy value as oname */
            while (*val != '\0' && *val != ';') {        //printf (".... %c\n", *val);
                *oname++ = *val++;
            }
            *oname = '\0';
        
        bail:    return ret;
        }static int get_oname_from_url(char const* url, char *oname){    int         ret = 0;    char const  *u  = url;    /* Remove "http(s)://" */
            u = strstr(u, "://");    if (u) {
                u += strlen("://");
            }
        
            u = strrchr(u, '/');    /* Remove last '/' */
            u++;    /* Copy value as oname */
            while (*u != '\0') {        //printf (".... %c\n", *u);
                *oname++ = *u++;
            }
            *oname = '\0';    return ret;
        }size_t dnld_header_parse(void *hdr, size_t size, size_t nmemb, void *userdata){    const   size_t  cb      = size * nmemb;    const   char    *hdr_str= hdr;
            dnld_params_t *dnld_params = (dnld_params_t*)userdata;    char const*const cdtag = "Content-disposition:";    /* Example: 
             * ...
             * Content-Type: text/html
             * Content-Disposition: filename=name1367; charset=funny; option=strange
             */
            if (strstr(hdr_str, "Content-disposition:")) {        printf ("has c-d: %s\n", hdr_str);
            }    if (!strncasecmp(hdr_str, cdtag, strlen(cdtag))) {        printf ("Found c-d: %s\n", hdr_str);        int ret = get_oname_from_cd(hdr_str+strlen(cdtag), dnld_params->dnld_remote_fname);        if (ret) {            printf("ERR: bad remote name");
                }
            }    return cb;
        }
        
        FILE* get_dnld_stream(char const*const fname)
        {    char const*const pre = "/tmp/";    char out[4096];    snprintf(out, sizeof(out), "%s/%s", pre, fname);
        
            FILE *fp = fopen(out, "wb");    if (!fp) {        printf ("Could not create file %s\n", out);
            }    return fp;
        }size_t write_cb(void *buffer, size_t sz, size_t nmemb, void *userdata){    int ret = 0;
            dnld_params_t *dnld_params = (dnld_params_t*)userdata;    if (!dnld_params->dnld_remote_fname[0]) {
                ret = get_oname_from_url(dnld_params->dnld_url, dnld_params->dnld_remote_fname);
            }    if (!dnld_params->dnld_stream) {
                dnld_params->dnld_stream = get_dnld_stream(dnld_params->dnld_remote_fname);
            }
        
            ret = fwrite(buffer, sz, nmemb, dnld_params->dnld_stream);    if (ret == (sz*nmemb)) {
               dnld_params->dnld_file_sz += ret;
            }    return ret;
        }int download_url(char const*const url){
            CURL        *curl;    int         ret = -1;
            CURLcode    cerr = CURLE_OK;
            dnld_params_t dnld_params;    memset(&dnld_params, 0, sizeof(dnld_params));    strncpy(dnld_params.dnld_url, url, strlen(url));
        
            curl = curl_easy_init();    if (!curl) {        goto bail;
            }    cerr = curl_easy_setopt(curl, CURLOPT_URL, url);    if (cerr) { printf ("%s: failed with err %d\n", "URL", cerr); goto bail;}    cerr = curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, dnld_header_parse);    if (cerr) { printf ("%s: failed with err %d\n", "HEADER", cerr); goto bail;}    cerr = curl_easy_setopt(curl, CURLOPT_HEADERDATA, &dnld_params);    if (cerr) { printf ("%s: failed with err %d\n", "HEADER DATA", cerr); goto bail;}    cerr = curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_cb);    if (cerr) { printf ("%s: failed with err %d\n", "WR CB", cerr); goto bail;}    cerr = curl_easy_setopt(curl, CURLOPT_WRITEDATA, &dnld_params);    if (cerr) { printf ("%s: failed with err %d\n", "WR Data", cerr); goto bail;}    cerr = curl_easy_perform(curl);    if(cerr != CURLE_OK) {        fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(cerr));
            }    printf ("Remote name: %s\n", dnld_params.dnld_remote_fname);
            fclose(dnld_params.dnld_stream);    /* always cleanup */
            curl_easy_cleanup(curl);
            ret = 0;    printf ("file size : %lu\n", dnld_params.dnld_file_sz);
        
        bail:    return ret;
        }int main(int argc, char *argv[]){    if (argc != 2) {        printf ("Bad args\n");        return -1;
            }    return download_url(argv[1]);
        }

        http://www.voidcn.com/article/p-zedgciid-bxs.html

        *博客內容為網友個人發布,僅代表博主個人觀點,如有侵權請聯系工作人員刪除。

        DIY機械鍵盤相關社區:機械鍵盤DIY




        關鍵詞: curl

        技術專區

        關閉
        主站蜘蛛池模板: 遂平县| 朔州市| 陆川县| 邵东县| 慈利县| 长阳| 平潭县| 博爱县| 大理市| 山阳县| 阳曲县| 岢岚县| 保定市| 扶风县| 太白县| 九龙坡区| 双牌县| 囊谦县| 天柱县| 明光市| 东港市| 疏勒县| 连平县| 曲沃县| 宁陕县| 平度市| 板桥市| 纳雍县| 晋城| 封丘县| 亚东县| 秦皇岛市| 湖北省| 太白县| 石景山区| 呼伦贝尔市| 花莲市| 保亭| 正定县| 客服| 嘉义市|