简体   繁体   中英

Libcurl: image is damaged when using fstream::write instead of fwrite

I'm trying to download image file from a url. I followed the example using fwrite and it succeeded. Now I'm trying to use fstream::write to save the data ( ios::binary ), but the data is damaged . Here is my code:

#include"stdafx.h"
#include<fstream>
#include<iostream>
#include <curl/curl.h>
#include <string.h>

using namespace std;

size_t write_data(void *ptr, size_t size, size_t nmemb, char* out) {
    //void *ptr, size_t size, size_t nmemb, File* fp

    fstream file;
    if (file.is_open()){
        file.close();
        file.clear();
    }
    file.open(out, ios::out | ios::binary);
    if (file.is_open()){
        cout << "open successfully\n" << endl;

        file.write((char*)ptr, nmemb*size);  // Does it correct?
    };
    // fwrite(ptr,size,nmemb,fp);
    file.close();
    file.clear();
    cout <<"\n sizeof(ptr): " << sizeof(ptr) //size of ptr[0]?
         <<"\n sizeof(char): " << sizeof(char)
         <<"\n size: " << size
         <<"\n nmemb: " << nmemb<< endl;
         return size*nmemb;
}

I'm confused about the parameters in write_data. According to CURLOPT_WRITEFUNCTION

size_t write_callback(char *ptr, size_t size, size_t nmemb, void *userdata);

" ptr points to the delivered data, and the size of that data is size multiplied with nmemb ."

......so what are the meanings of size and nmemb?

When tried to download the data from a website,I printed first 3 parameters. It seems that char*ptr is the memory address that data stored (as 'char a[]'?), and size is element's size, nmemb is number of the elements. So the data size = size * nmemb. Am I correct?

The output is confusing too:

open successfully
sizeof(ptr):4
sizeof(char):1
size:1
nmemb:2715 
open successfully
sizeof(ptr):4
sizeof(char):1
size:1
nmemb:4865
download successfully

When download the same url, nmemb and files' open times often change.

I'm also confused about 'sizeof(ptr)', it returns '4'(size of int?). How can I use the 'sizeof' to get the size of data memory, so that I can proof that data size is 'size * nmemb'?

CURLcode download(char* url,char* out){
    CURL *curl = NULL;
    //FILE *fp = NULL;
    CURLcode res;
    curl = curl_easy_init();
    if (curl) {
        curl_easy_setopt(curl, CURLOPT_URL, url);
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, out);    //fp
        res = curl_easy_perform(curl);
        curl_easy_cleanup(curl);
        return res;
    }
    else
    {
        return CURLE_FAILED_INIT;
    }
}    

int main()
{
    CURLcode res = download("http://XXXXXX.gif", "D:\\test.gif");
    if (CURLE_OK == res)
        cout << "download successfully.\n" << endl;
    else
        cout<<"cannot download.\n"<<endl;
    return 0;
}

Thanks! :)

This callback can be multiple times per file. You should NOT create a new file stream every time the function is called - you should pass it in using the user data parameter. Otherwise you will just keep overwriting the data at the beginning of the file.

Here is an example implementation:

size_t write_data(char *ptr, size_t size, size_t nmemb, void *userdata)
{
    std::ofstream *out = static_cast<std::ofstream *>(userdata);
    size_t nbytes = size * nmemb;
    out->write(ptr, nbytes);
    return nbytes;
}

You also need to adjust the call to curl_easy_setopt with the parameter CURLOPT_WRITEDATA to actually pass your file stream. Make sure that the stream does not go out of scope while the functions run!

CURLcode download(char* url, char* out) {
    CURL *curl = NULL;
    std::ofstream output(out, ios::binary);
    CURLcode res;
    curl = curl_easy_init();
    if (curl) {
        curl_easy_setopt(curl, CURLOPT_URL, url);
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, &output);
        res = curl_easy_perform(curl);
        curl_easy_cleanup(curl);
        return res;
    }
    else
    {
        return CURLE_FAILED_INIT;
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM