c ++ FILE struct参数含义

时间:2013-08-19 14:51:24

标签: c++ file curl io

现在使用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计算公式参数。

据我所知FILE struct有一个名为_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;
}

在我附加此函数将数据打印到屏幕后,我看到它打印了大量垃圾,所以我的问题是,如何获取数据缓冲区大小?

2 个答案:

答案 0 :(得分:1)

FILE的内容是不透明的,并且是一个实现 只提供了前瞻性参考,因为它符合要求。 这将是一个罕见的实施,保持一切 缓冲区。你想要做的是计算你的MD5 你传递给fwrite的缓冲区。

至于你的第二个例子:

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

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

答案 1 :(得分:1)

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

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

正是对于这种应用程序,libcurl为您提供了设置自己的用户数据的可能性,而不仅仅是传递文件*。

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

// 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;
}