libcurl动态压缩下载的数据

时间:2013-03-26 07:56:28

标签: c linux libcurl

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

2 个答案:

答案 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);