在C/C++中使用libcurl下载文件

69
2个回答

210
您所使用的示例有误。请参阅 easy_setopt 的 man 页面。在该示例中,write_data 使用自己的 FILE,*outfile,并不是在 CURLOPT_WRITEDATA 中指定的 fp。这就是为什么关闭 fp 会导致问题 - 它甚至没有被打开。以下是更正确的实现方式(因无法测试,仅供参考)。
#include <stdio.h>
#include <curl/curl.h>
/* For older cURL versions you will also need 
#include <curl/types.h>
#include <curl/easy.h>
*/
#include <string>

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(void) {
    CURL *curl;
    FILE *fp;
    CURLcode res;
    char *url = "http://localhost/aaa.txt";
    char outfilename[FILENAME_MAX] = "C:\\bbb.txt";
    curl = curl_easy_init();
    if (curl) {
        fp = fopen(outfilename,"wb");
        curl_easy_setopt(curl, CURLOPT_URL, url);
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
        res = curl_easy_perform(curl);
        /* always cleanup */
        curl_easy_cleanup(curl);
        fclose(fp);
    }
    return 0;
}

更新:如 @rsethc 建议,types.heasy.h 不再存在于当前 cURL 版本中。


1
我在OSX上尝试了这个,但是出现了以下错误警告:warning: deprecated conversion from string constant to ‘char’ 未定义符号: "___gxx_personality_v0", 在以下中引用: _main in ccHRyU1T.o write_data(void, unsigned long, unsigned long, __sFILE*)in ccHRyU1T.o CIE in ccHRyU1T.o ld: 找不到符号 collect2: ld 返回了 1 个退出状态 请帮忙解决!! - TCB13
1
Libcurl有自己的内部函数用于将数据写入文件,其功能与上述“write_data”完全相同。无需编写“write_data”,也无需设置“CURLOPT_WRITEFUNCTION”。只需设置“CURLOPT_WRITEDATA”并保持“CURLOPT_WRITEFUNCTION”不变-您将获得相同的功能。 - AnT stands with Russia
1
在我的电脑上,我不得不删除 #include <string>。我尝试编译为C和C++。在这两种情况下,示例立即返回并且文件为空白。 - PPP
这个能用于 SSL 吗?有人可以帮帮我吗? - Ahmed Can Unbay
正如@AnT-StoptheUkroNazis所说,如果您想将其写入FILE *,则无需自己编写WRITEFUNCTION代码,FILEDATA文档中说:**如果您使用CURLOPT_WRITEFUNCTION选项,则这是回调的第4个参数中将获得的指针。如果您不使用写回调,则必须将指针作为“FILE ”(转换为“void ”)使libcurl在写入数据时将其传递给fwrite(3)。 - masterxilo
显示剩余4条评论

31

对于那些感兴趣的人,您可以通过将最后一个参数设为NULL来避免编写自定义函数(如果您不打算对返回的数据进行额外处理)。

在这种情况下,将使用默认的内部函数。

详情请参阅:
http://curl.haxx.se/libcurl/c/curl_easy_setopt.html#CURLOPTWRITEDATA

示例:

#include <stdio.h>
#include <curl/curl.h>

int main(void)
{
    CURL *curl;
    FILE *fp;
    CURLcode res;
    char *url = "http://stackoverflow.com";
    char outfilename[FILENAME_MAX] = "page.html";
    curl = curl_easy_init();                                                                                                                                                                                                                                                           
    if (curl)
    {   
        fp = fopen(outfilename,"wb");
        curl_easy_setopt(curl, CURLOPT_URL, url);
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, NULL);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
        res = curl_easy_perform(curl);
        curl_easy_cleanup(curl);
        fclose(fp);
    }   
    return 0;
}

1
在Windows上这不起作用。在Windows上,您必须将CURLOPT_WRITEFUNCTION设置为非空,否则会导致崩溃。请参阅https://curl.haxx.se/libcurl/c/CURLOPT_WRITEDATA.html。 - Phil Rosenberg
@PhilRosenberg好像很不幸,因为在这里https://curl.haxx.se/libcurl/c/CURLOPT_WRITEFUNCTION.html#DESCRIPTION中明确说明:“将此选项设置为NULL以获得内部默认函数,而不是使用回调。“所以,“如果您正在使用libcurl作为win32 DLL,则必须使用CURLOPT_WRITEFUNCTION(如果设置此选项)或您将遇到崩溃。“应该没有影响,因为再次使用内部函数。 - Petar
1
这个例子立即返回,我得到了一个空文件。 - PPP
Wireshark检查显示该页面返回了302永久移动,然后您会得到0字节的输出。调用像pudim.com.br这样返回200的网站是有效的。 - Guerlando OCs
2
@GuerlandoOCs,这与示例没有直接关系,如果要支持重定向,请使用https://curl.se/libcurl/c/CURLOPT_FOLLOWLOCATION.html。 - Petar
由于您设置了res变量,因此值得使用它,并使用严格的设置:error: variable 'res' set but not used [-Werror=unused-but-set-variable] - Antonio

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接