0

现在使用curl并具有回调函数将结果存储到文件中:

size_t WriteData(void *ptr, size_t size, size_t nmemb, FILE *stream) 
{
    size_t written = fwrite(ptr, size, nmemb, stream);
    return written;
}

我还需要计算MD5收到的文件。但是再次读取下载的文件来计数MD5是个坏主意,所以我想获得一个存储到文件中的缓冲区,将其用作部分MD5计算公式参数。

据我了解, FILEstruct 有一个名为的成员_base,所有要写入文件的数据都保存在其中,但是我需要知道它的大小。正如我认为的大小应该是nmemb,但我做了小测试:

size_t WriteData(void *ptr, size_t size, size_t nmemb, FILE *stream) 
{
    size_t written = fwrite(ptr, size, nmemb, stream);
    for (int i = 0; i < nmemb; ++i)
        std::cout << stream->_base[i];
    return written;
}

在我将此功能附加到将数据打印到屏幕上后,我看到它会打印很多垃圾,所以我的问题是,如何获取数据缓冲区大小?

4

2 回答 2

1

的内容FILE是不透明的,并且仅为其提供前向引用的实现将符合要求。这将是一种罕见的实现,它将所有内容都保存在缓冲区中。你想要做的是计算MD5你传入的缓冲区fwrite

至于你的第二个例子:

std::cout << std::string( static_cast<char const*>( ptr ), size * nmemb );

但这仅在您实际编写文本数据时才有效。

于 2013-08-19T15:11:32.333 回答
1

(注意:这是我认为应该问的问题的答案,而不是实际问的问题。请参阅https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem

您应该只为 libcurl 提供您自己的用户数据,而不是弄乱 C 库的内部结构,这绝不是一个好主意。您可以在CURLOPT_WRITEDATA初始化传输时使用选项设置用户数据。

正是针对此类应用程序,libcurl 为您提供了设置自己的用户数据的可能性,而不仅仅是传递 FILE*。

粗略地说,代码看起来像这样:

// All error checking has been omitted; don't use this code as is.

// This is the userdata you'll be using
typedef struct FileWithMD5 {
  FILE*   file;
  MD5_CTX md5_ctx;
} FileWIthMD5;

// The transfer function we'll be using
size_t write_with_md5(char *ptr, size_t size, size_t  nmemb,
                      void *userdata);

// This function is called before the transfer is started.
// The return value needs to be passed to the finalize function.
FileWithMD5* initialize_transfer(CURL *handle, const char* filename) {
  // Allocate a userdata
  FileWithMD5* userdata = malloc(sizeof(*userdata));
  userdata->file = fopen(filename, "w");
  MD5Init(&userdata->md5_ctx);
  curl_easy_setopt(handle, CURL_WRITEDATA, userdata);
  curl_easy_setopt(handle, CURL_WRITEFUNCTION, write_with_md5);
  return userdata;
}

// This function is called after the transfer is finished.
void finalize_transfer_and_extract_md5(CURL *handle,
                                       FileWithMD5* userdata,
                                       u_int8_t md5[MD5_DIGEST_LENGTH]) {
  // Close the file, extract the MD5, and get rid of the userdata
  close(userdata->file);
  MD5Final(md5, &userdata->md5_ctx);
  free(userdata);
  curl_easy_setopt(handle, CURL_WRITEDATA, 0);
}

// Callback function
size_t write_with_md5(char *ptr, size_t size, size_t  nmemb,
                      void *vuserdata) {
  FileWithMD5* userdata = vuserdata;
  // Write the data and update the MD5
  size_t written = fwrite(ptr, size, nmemb, userdata->file);
  MD5Update(&userdata->md5_ctx, (const u_int8_t*)ptr, written);
  return written;
}
于 2013-08-19T15:24:59.120 回答