2012-01-17 125 views
13

我正在使用zlib来压缩文本数据流。文本数据以块形式显示,并且对于每个块,调用deflate(),并将刷新设置为Z_NO_FLUSH。一旦检索到所有块,则调用deflate()并将flush设置为Z_FINISHzlib,deflate:要分配多少内存?

自然地,deflate()在每次调用时都不会产生压缩输出。它在内部累积数据以实现高压缩率。那很好!每当deflate()产生压缩输出时,该输出都附加到数据库字段 - 一个缓慢的过程。

但是,一旦deflate()产生压缩数据,该数据可能不适合提供的输出缓冲区deflate_out。因此需要拨打deflate()的多个电话。这就是我想要的东西,以避免:

有没有一种方法,使deflate_out总是足够大,以便deflate()可以存储在它所有的压缩数据,它决定产生输出每一个时间?

注:

  • 未压缩数据的总大小是事先知道的。如上所述,未压缩的数据以块的形式出现,压缩的数据也以块的形式附加到数据库字段。

  • 在包含文件zconf.h中,我发现了以下评论。这可能是我在找什么?即(1 << (windowBits+2)) + (1 << (memLevel+9))deflate()可能产生的压缩数据的最大字节数是多少?

    /* The memory requirements for deflate are (in bytes): 
          (1 << (windowBits+2)) + (1 << (memLevel+9)) 
    that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) 
    plus a few kilobytes for small objects. For example, if you want to reduce 
    the default memory requirements from 256K to 128K, compile with 
        make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" 
    Of course this will generally degrade compression (there's no free lunch). 
    
        The memory requirements for inflate are (in bytes) 1 << windowBits 
    that is, 32K for windowBits=15 (default value) plus a few kilobytes 
    for small objects. 
    */ 
    
+0

查看http://stackoverflow.com/questions/4936255/zlib-how-to-dimension-avail-out – nos 2012-01-17 23:17:00

+2

@nos:这只是有用的,如果输入的大小是已知的。 – 2012-01-17 23:19:22

+0

我读'zconf.h'中的注释是压缩的内存要求,而不是输出缓冲区的大小。 这就是说,它似乎是合乎逻辑,即一个上界输出缓冲器是总的内存要求(128K + 128K +“几千字节”在上面的例子)+标题长度(40字节)。 – 2012-01-17 23:29:51

回答

5

只有在单个步骤中完成所有压缩,或者强制压缩才能压缩当前可用的所有输入数据并为所有输入发出压缩数据时,deflateBound()才有用。你可以使用Z_BLOCK,Z_PARTIAL_FLUSH等刷新参数来做到这一点。

如果你想使用Z_NO_FLUSH,那么试图预测最大的输出deflate()可能会变得困难和低效在下一次呼叫时发出。您不知道在发送最后一批压缩数据时输入了多少输入,因此您需要几乎不假设它,缓冲区大小不必要地增加。然而,你试图估计最大输出,你会做很多不必要的malloc或reallocs,这是没有道理的,这是低效的。

没有必要避免为更多输出调用deflate()。如果你直接在deflate()上循环,直到它没有更多的输出,那么你可以使用一个固定的输出缓冲区malloced一次。这就是deflate()和inflate()接口的设计方式。您可以查看http://zlib.net/zlib_how.html了解如何使用该界面的完整文档示例。

顺便说一句,有在zlib的(1.2.6)的最新版本deflatePending()函数,可以让你知道多少输出放气()已等待交付。

+0

非常感谢您的详细解答!为了预测下一次调用deflate()所需的输出缓冲区,我考虑添加由deflatePending()报告的大小和由deflateBound()返回的值。这与@EugenRieck的建议类似。然而,据我了解,这不是一个好主意,因为'deflateBound()'被记录为只有在传递了要压缩的整个输入的大小时才起作用。即'deflateBound()'没有被记录为适用于输入块。 – feklee 2012-01-31 21:56:45

+1

deflateBound()可以工作,输入的块,但只有当所有以前输入的被压缩和发射。这只能通过使用除Z_NO_FLUSH以外的刷新选项并使用前面调用的所有输出来保证。在这种情况下,当使用Z_BLOCK或Z_PARTIAL_FLUSH时,deflatePending()会很有用,因为它们可能会留下几位。当使用Z_NO_FLUSH时,deflateBound()+ deflatePending()会丢失第三块,这是以前deflate()调用所消耗的输入大小,但尚未压缩和发射。 – 2012-02-04 20:12:49

2

在注视来源的提示,我跌倒

/* ========================================================================= 
* Flush as much pending output as possible. All deflate() output goes 
* through this function so some applications may wish to modify it 
* to avoid allocating a large strm->next_out buffer and copying into it. 
* (See also read_buf()). 
*/ 
local void flush_pending(strm) 
    z_streamp strm; 
{ 
    unsigned len = strm->state->pending; 
... 

跟踪使用空隙flush_pending()的整个放气()所示,其上所需要的上限输出缓冲区在流的中间是

strm->state->pending + deflateBound(strm, strm->avail_in) 

第一部分考虑到仍然存在于以前调用管道中的数据为了deflate(),第二部分解释了尚未处理的长度为avail_in的数据。

+0

你对我现在删除的答案的评论是正确的。我忘记了内部状态。出于好奇,我在第一次呼叫之后查看了待定值,在快速测试中放气。 avail_in为零,avail_out为2,待处理为零(0)。它似乎没有反映未决数据的实际数量。下一次放气冲洗的呼叫将〜8K倾倒到输出。所以这可能不是一个准确的测量......至少在一种情况下。 – 2012-01-18 00:54:08

+0

你说'strm-> state-> pending'是*数据仍在管道*中的大小。如果我理解正确,那么随着每次调用deflate(),这个大小都会增加,直到达到未知的上限。而这个上限正是我正在寻找的。那么这有什么用呢?我错过了什么吗? – feklee 2012-01-18 20:45:09

+0

我的意思是,如果你给放气()大小的缓冲区strm->国有>待定+ deflateBound(STRM,strm-> avail_in)它永远不会用完的缓冲空间。 – 2012-01-18 21:19:17