2016-07-01 3 views
1

私は、並列CPUスレッドを使用してgzip(.gz)ファイルを生成することができます。つまり、個別に初期化されたz_streamレコードを持つ入力ファイルから別々のチャンクを収縮させることになります。個別に圧縮されたチャンクからgzipストリームを作成する

従来のシングルスレッド操作では、結果ファイルはzlibのinflate()関数で読み取ることができます。

これは可能ですか?カスタマイズされたzlibコードが必要な場合でも?唯一の要件は、現在存在するzlibのinflateコードがそれを処理できることです。

更新

pigzソースコードは、それがどのように動作するかを示しています。いくつかの洗練された最適化を使用してチャンク間で辞書を共有し、圧縮率を最適に保ちます。より新しいzlibバージョンが使用されている場合は、さらにビットパッキングを処理します。

どのように私は自分自身をロールバックする方法を理解したい、最適化せずに物事をシンプルに保つことが好きですpigzを使用します。

多くの場合、ソースコードは最終的なドキュメント(Ed Post, anyone?)であると考えていますが、誤解を避けるために、ソースコードを単純な言葉で説明しました。 (。ドキュメントは、実際にかなりよく何が起こるかを記載しているが、彼らは自分自身をロールするために何をすべきか、あまりにもうまく説明できない)

コードを閲覧から、私はこれまで多くを考え出し:

それZ_FINISHの代わりに、deflate(..., Z_SYNC_FLUSH)を使用して各圧縮チャンクを作成するだけです。しかし、deflateEnd()はエラーを返し、無視できるかどうかはわかりません。最後にチェックサムを追加する方法は不思議ですが、手作業ですべてのチャンクに対する最終チェックサムを手動で計算する必要があります。また、gzipヘッダーを書くためのかなり複雑なput_trailer()関数もあります。単純なケースのためにzlib自身のコードでも扱えるのだろうか?

これについての説明は理解できます。

また、マルチスレッド圧縮ファイルをzipアーカイブに書き込むために、同じ方法でzlibストリームを書き込むことを尋ねる必要があります。より複雑なgzipヘッダーがないため、より単純化が可能です。

答えて

3

答えはあなたの質問です。各スレッドには、供給されたデータのチャンクを圧縮する生のデフレートデータ(deflateInit2()を参照)を生成するための独自のdeflateインスタンスがあり、Z_FINISHの代わりにZ_SYNC_FLUSHで終わります。データの最後の部分を除いて、Z_FINISHで終わります。どちらの方法でも、これは圧縮データの各結果ストリームをバイト境界で終了させます。生成されたすべてのデータがdeflate()から抜けていることを確認してください。次に、すべての圧縮データストリームを連結することができます。 (正しい順序で!)あなた自身を生成するgzipヘッダーを前に付けてください。それは簡単です(RFC 1952参照)。ヘッダーに追加の情報(ファイル名、変更日など)を追加する必要がない場合は、定数10バイトのシーケンスにすることができます。 gzipヘッダーは複雑ではありません。

また、同じスレッドまたは別のスレッド内の圧縮されていない各チャンクのCRC-32を計算し、crc32_combine()を使用してこれらのCRC-32を組み合わせることもできます。 gzipの予告編に必要です。

すべての圧縮ストリームが書き込まれた後、圧縮ストリームの末尾がZ_FINISHで終了すると、gzipの予告編が追加されます。すべてがリトルエンディアンの順序で、4バイトのCRC-32と合計の非圧縮の長さの下位4バイトです。合計8バイト。

各スレッドでは、各チャンクで完了したときにdeflateEnd()を使用するか、より多くのチャンクに対してスレッドを再利用する場合はdeflateReset()を使用します。私は、複数のチャンクを処理するときに、スレッドを開いたままにして、deflateのインスタンスを開いておく方がはるかに効率的であることをpigzに発見しました。スレッドを閉じる前に、スレッド処理の最後のチャンクにはdeflateEnd()を必ず使用してください。はい、deflateEnd()のエラーは無視できます。 avail_outがゼロでないときまでdeflate()を実行して圧縮データをすべて取得したことを確認してください。

これを行うと、各スレッドはそのチャンクを他の圧縮されていないデータへの参照なしに圧縮します。さらに進歩させたい場合は、各スレッドに非圧縮データのチャンクを圧縮して圧縮することができます。は、前のチャンクの最後の32Kで圧縮プログラムの履歴を提供します。これはdeflateSetDictionary()で行います。

さらに高度な機能を使用すると、圧縮ストリーム間に挿入されるバイト数を減らすことができ、バイト境界に達するまでZ_PARTIAL_FLUSHを使用することがあります。その詳細についてはpigzを参照してください。

さらに進歩しましたが、速度は遅く、バイトレベルではなくビットレベルで圧縮ストリームを追加できます。そのためには、圧縮されたストリームのすべてのバイトを2回シフトして、新しいシフトされたストリームを構築する必要があります。先行する8つの圧縮ストリームのうち少なくとも7つの圧縮ストリーム。これにより、圧縮されたストリーム間に挿入された余分なビットがすべて削除されます。

zlibストリームは、全く同じ方法で、チェックサムにadler32_combine()を使用して生成することができます。

zlibについてのご意見は、混乱を意味します。 zip形式では、zlibヘッダーとトレーラーは使用されません。 zip has its own structureであり、その中に生の収縮ストリームが埋め込まれている。それらの未処理のデフレートストリームについても上記の方法を使用できます。

+0

私は自分のgzヘッダーとトレーラーを追加して、deflateを使用しようとしています。ビット4をwビットで設定すると、gzファイルは10バイトのヘッダ「1F 8B 08 00 00 00 00 00 03」で始まり、データ '95 58 7B 6F D3 48 ...'が収縮し、CRCで終わり、ソース長さここまでは順調ですね。ビット4がクリアされると、それは '78 DA'で始まり、次に同じデータ' 95 58 7B 6F D3 48 ... 'で始まり、チェックサム(Adler?)で終わります。最初の2バイトは何をしますか?ヘッダーを追加してCRCとoriglenを追加するだけで、.gzファイルとして解凍されません。ヘッダーとトレーラーなしで純粋なgzストリームを生成するにはどうすればよいですか? –

+0

私はあなたが「生の収縮ストリームをどのように生成するのですか?ヘッダーと予告編がない場合は、定義上gzipまたは "gz"ストリームではありません。 zlib.hのドキュメントには、raw deflateストリームの作成方法が記載されています。 'deflateInit2()'に負の 'wbits'値を与えます。 –

+0

zlibストリームの最初の2バイトは、それをzlibストリームとして識別し、圧縮方法とウィンドウサイズを提供します。最後に、Adler-32の値はビッグエンディアンの順序で格納されます。 (gzipラッパーとは異なり、トレーラーの値はリトルエンディアンの順番で格納されます) –

1

確か..

http://zlib.net/pigz/

現代 マルチプロセッサ、マルチコアマシン用のgzipの並列実装

+0

ニート。今では、標準のzlib関数を使用するための独自のpthreadベースのコードをすでに作成しているので、deflateInit2でこの作業を行うためにどのオプションを使用する必要があるか、またはこの機能が実際に書き換えられたzlibを必要とするかどうかつまり、私はこのためにpigzを使う必要がありますか?あなたは知っていますか? (ホールド、現在のソースコードを読んで...) –

+0

いいえ、deflateInit2が何を意味するのかわからないし、プログラミングでこれを使用していない。しかし、私はピッグ圧縮されたファイルはgunzipを使って解凍できることを知っているので、gzipが正しく扱えるようにフォーマットする必要があります。 – thelogix

関連する問題