2016-08-01 11 views
2

chipz decompression libraryには非常に便利な機能があります。は、提供されたストリームから読み取られたデータを透過的に解凍するためのインターフェイス(舞台裏でグレーストリームを使用)を提供します。これにより、圧縮されたデータと圧縮されていないデータの両方で動作するCommon Lispのread関数がストリームから単一のLisp "フォーム"を読み込むのと同じように、単一の関数read-tag(構造化バイナリデータのストリームから単一の "タグ"例えば:Common Lispでデータを圧縮するストリームインターフェイス

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

私の知る限り、関連する圧縮ライブラリ、salza2のAPIは、逆のタスクを実行するための(アウトオブボックス)同等のインターフェースを提供していません。どうやってこのようなインターフェースを自分で実装できますか?それをmake-compressing-streamとしましょう。それは私自身の補完的なwrite-tag機能を使用し、読書のためのと同じ利点を提供します。(上記のリンク)salza2のマニュアルで

;; 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が作成するためのインタフェースを提供します圧縮されたオクテットデータは、ユーザ定義のコールバックに提供されます。このコールバックにより、圧縮されたオクテットデータは、オクテットに書き込むことができます。ストリーム、別のベクトルなどにコピーします。私の現在の目的では、zlibとgzip形式の圧縮が必要です。標準の圧縮器が提供されています。

私はそれを行うことができると思います:まず、 "タグ"オブジェクトをオクテットベクトルに変換し、次にsalza2:compress-octet-vectorを使用して圧縮し、第3に圧縮データを直接ファイルに書き込むコールバック関数を提供します。読んで、私は最初のステップはflexi-streams:with-output-to-sequence - hereを参照して達成することができると思うが、私は本当にsalza2のソースを見ても、コールバック関数についてはよく分かりません。しかし、ここでは、1つのタグに任意の数の任意にネストされたタグを含めることができます。この構造の「リーフ」タグには、大きなペイロードがそれぞれ含まれています。言い換えれば、単一のタグは非常に多くのデータになる可能性があります。

tag-> uncompressed-octets-> compressed-octets->ファイル変換は、理想的にはチャンクで実行する必要があります。これにより、答えがわからないという質問が発生します。圧縮形式 - AIUI - ヘッダーにペイロードデータのチェックサムを格納する傾向があります。一度にデータを1つのチャンクに圧縮し、圧縮された各チャンクを出力ファイルに追加すると、タグ全体のデータの1つのヘッダーとチェックサムとは対照的に、各チャンクのヘッダーとチェックサムが確実に存在します。欲しいです?どうすればこの問題を解決できますか?それとも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は、圧縮されたデータの2つの連続したチャンクが含まれています。 呼び出しdecompressのみ、最初のチャンク読み:

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

chipzのソースを見ると、ストリームはおそらく既に読まなく、解凍されていない最初のチャンクを次のバイトを意味し、内部バッファを使用して読み込まれます。つまり、2つの連続したコールを同じストリームで使用すると、2つ目のエラーは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を参照)。