2012-01-17 69 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