1

Linux。libcurlを介して大量のデータをダウンロードしています。データのエントロピーは低くなりますが、サイズは大きくなります(数十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);
}
4

2 に答える 2

1

サーバー側で何が起こるかを制御しますか?

はいの場合、libcurl側でコンテンツのデコードをオフにしながら、すでにGZIP化されたコンテンツを要求するのはどうですか?続行する方法は次のとおりです(メーリングリストに関する最近の議論から):デコードせずにエンコードを要求します

それ以外の場合は、ストリーミング機能を提供するlibarchiveなどのライブラリ(たとえば、 libcurlを使用したHTMLストリーミングパーサー)でうまくいくはずです。

-

更新: zlibでオンザフライ圧縮を使用するサンプルコードは次のとおりです:https ://github.com/deltheil/zurl 。

于 2013-03-26T10:55:14.397 に答える
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);
于 2013-03-28T15:38:58.360 に答える