2016-08-01 37 views
2

chipz decompression library中有一個非常有用的函數make-decompressing-stream,它提供了一個接口(在後臺使用Gray流)來透明地解壓縮從提供的流中讀取的數據。這允許我編寫一個函數read-tag(它從結構化二進制數據流中讀取單個「標籤」,就像Common Lisp的read函數從流中讀取單個Lisp「表單」一樣)可以處理壓縮和未壓縮的數據例如:在Common Lisp中用於數據壓縮的流接口

;; For uncompressed data: 
(read-tag in-stream) 
;; For compressed data: 
(read-tag (chipz:make-decompressing-stream 'chipz:zlib in-stream)) 

據我所知,相關壓縮的API庫salza2,不用於進行反向任務提供一種(外的現成)等效接口。我怎麼能自己實現這樣一個接口?我們稱之爲make-compressing-stream。它會用我自己的互補write-tag功能一起使用,並提供同樣的好處閱讀:

;; For uncompressed-data: 
(write-tag out-stream current-tag) 
;; For compressed data: 
(write-tag (make-compressing-stream 'salza2:zlib-compressor out-stream) 
       current-tag) 

在salza2的文檔(上面鏈接),在概述,它說:「Salza2提供一個接口,用於創建壓縮器對象這個對象作爲八位字節(單個或八位字節向量)的接收器,並且是壓縮數據格式的八位字節的源。壓縮的八位字節數據被提供給用戶定義的回調函數,可以將其寫入流,將其複製到另一個矢量等。「就我目前的目的而言,我只需要以zlib和gzip格式進行壓縮,而標準壓縮器就是這種格式。第一,將我的「標籤」對象轉換爲八位字節向量,然後使用salza2:compress-octet-vector對其進行壓縮,第三,提供一個回調函數,將壓縮數據直接寫入文件。從閱讀的角度來看,我認爲可以使用flexi-streams:with-output-to-sequence來實現第一步 - 請參閱here - 但我真的不確定回調函數,儘管查看salza2的來源。但是事情是這樣的:一個標籤可以包含任意數量的任意嵌套標籤,並且這個結構的「葉子」標籤可以分別攜帶一個相當大的有效負載;換句話說,一個標籤可以是相當多的數據。

因此,標記 - >未壓縮字節 - >壓縮字節 - >文件轉換理想情況下需要在塊中執行,這就產生了一個問題,我不知道如何回答,即:壓縮格式 - AIUI-傾向於在他們的頭部中存儲他們的有效載荷數據的校驗和;如果我一次壓縮數據塊並將每個壓縮塊附加到輸出文件,那麼肯定會有每個塊的頭和校驗和,而不是單個頭和整個標籤數據的校驗和,這就是我想?我怎麼解決這個問題?或者它已經被salza2處理了?

感謝您的幫助,對不起散漫:)

回答

2

據我所知,你不能直接從一個單一的文件解壓縮多塊。

(defun bytes (&rest elements) 
    (make-array (length elements) 
    :element-type '(unsigned-byte 8) 
    :initial-contents elements)) 

(defun compress (chunk &optional mode) 
    (with-open-file (output #P"/tmp/compressed" 
          :direction :output 
          :if-exists mode 
          :if-does-not-exist :create 
          :element-type '(unsigned-byte 8)) 
    (salza2:with-compressor (c 'salza2:gzip-compressor 
           :callback (salza2:make-stream-output-callback output)) 
     (salza2:compress-octet-vector chunk c)))) 

(compress (bytes 10 20 30) :supersede) 
(compress (bytes 40 50 60) :append) 

現在,/tmp/compressed包含兩個連續的壓縮數據塊。 調用decompress僅讀取第一個塊:

(chipz:decompress nil 'chipz:gzip #P"/tmp/compressed") 
=> #(10 20 30) 

chipz源尋找,流被使用內部緩衝器,這意味着,後面的第一個塊中的字節可能已經讀取而不能解壓縮的讀取。這就解釋了爲什麼當在同一個流上使用兩個連續的decompress調用時,第二個EOF錯誤。

(with-open-file (input #P"/tmp/compressed" 
         :element-type '(unsigned-byte 8)) 
    (list 
    #1=(multiple-value-list(ignore-errors(chipz:decompress nil 'chipz:gzip input))) 
    #1#)) 

=> ((#(10 20 30)) 
    (NIL #<CHIPZ:PREMATURE-END-OF-STREAM {10155E2163}>)) 

我不知道如何將數據大應該是,但如果它成爲一個問題,你可能需要改變解壓算法,這樣,當我們在done狀態(參見膨脹。 lisp)時,會返回足夠的數據以將剩餘字節處理爲新塊。或者,您壓縮到不同的文件並使用TAR等歸檔格式(請參閱https://github.com/froydnj/archive)。