Linux操作系统。我通过libcurl下载了大量数据。数据具有低熵但是巨大的尺寸(Tens of Gb)。目前我首先下载文件然后用zlib压缩它。
但这需要更多的时间和更多的空间。所以我试图在libcurl写回调中动态实现压缩
主要问题是要下载的数据的确切大小未知。代码很脏,但它只是一个测试。而且似乎这不是一条路。也许其他一些方式更合适?
unsigned char *outZ=malloc(1500);//Maximum write chunk is 1448
...
size_t
curl_write_func(void *ptr, size_t size, size_t nmemb, void *stream)
{
size_t data=zip(ptr,size*nmemb,outZ,1500,Z_FINISH);
fwrite(outZ, 1, data, (FILE *) stream);
return (size*nmemb);
}
size_t
zip(void *source, size_t src_size, void *target,size_t tgt_size, int mode)
{
z_stream strm;
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
deflateInit(&strm, Z_BEST_COMPRESSION);
strm.next_in = source;
strm.avail_in = src_size;
strm.next_out=target;
strm.avail_out=tgt_size;
deflate(&strm, mode);
deflateEnd(&strm);
return (tgt_size - strm.avail_out);
}
答案 0 :(得分:1)
你能控制服务器端发生的事情吗?
如果是,那么在关闭libcurl端的内容解码时要求已经GZIP内容的内容呢?以下是如何继续(从最近对邮件列表的讨论):request encoding without decoding。
否则像libarchive这样的库提供流媒体功能,以流方式(例如la HTML streaming parser with libcurl)提供应该可以解决问题。
-
更新:这是使用zlib进行动态压缩的示例代码:https://github.com/deltheil/zurl。
答案 1 :(得分:1)
最后我使用了原生的zlib库
它可能不够优雅,但我的C技能目前很差
一些变量必须是全局的,因为zlib流应该是不间断的
我压缩前一个块,因为最后一个块应该刷新,我没有找到通过libcurl调用确定它的方法。
因此,如果我们不使用easy_perform,那么前一个ine就是最后一个了
为清楚起见,省略了所有错误检查
还计算原始流的SHA1校验和
#define CHUNK 16384
SHA_CTX ctx;
z_stream strm;
unsigned char old_block[CHUNK];
unsigned char out[CHUNK];
unsigned have;
size_t prevBlkSize;
char firstIter;
size_t
curl_write_func(void *ptr, size_t size, size_t nmemb, void *stream)
{
//Stores the size of original data to write
size_t orig_size=size*nmemb;
if(firstIter)
{
memcpy(old_block,ptr,orig_size);
prevBlkSize=orig_size;
firstIter=0;
SHA1_Update(&ctx, ptr, orig_size);
return(orig_size);
}
//Compress old block with Z_NO_FLUSH
strm.avail_in=prevBlkSize;
strm.next_in = old_block;
do
{
strm.avail_out = CHUNK;
strm.next_out = out;
deflate(&strm, Z_NO_FLUSH);
have = CHUNK - strm.avail_out;
fwrite(out, 1, have, (FILE *) stream);
}
while (strm.avail_out == 0);
//
memcpy(old_block,ptr,orig_size);
prevBlkSize=orig_size;
SHA1_Update(&ctx, ptr, orig_size);
return (orig_size);
}
...
FILE *xva_export = fopen(xva_name, "wb");
//Prepare SHA1 and zlib
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
deflateInit(&strm, 9);
SHA1_Init(&ctx);
...
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_write_func);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, xva_export);
curl_easy_perform(curl);
curl_easy_cleanup(curl);
//Finish zlib
strm.avail_in=prevBlkSize;
strm.next_in = old_block;
do
{
strm.avail_out = CHUNK;
strm.next_out = out;
deflate(&strm, Z_FINISH);
have = CHUNK - strm.avail_out;
fwrite(out, 1, have, xva_export);
}
while (strm.avail_out == 0);
deflateEnd(&strm);
//SHA1 finish
SHA1_Final(hash, &ctx);
snprintf(sha1_name,sizeof(sha1_name),"%s.Z.sha1",xva_name);
FILE *sha1sum=fopen(sha1_name,"w");
for(int i=0; i<SHA_DIGEST_LENGTH; i++)
{
fprintf(sha1sum,"%x",hash[i]);
}
fclose(sha1sum);
fclose(xva_export);