1

非常に単純なものが欠けていると思います。デフレーターを使用して書き込まれたデフレートされたデータを保持するバイト配列があります。

deflate(outData, 0, BLOCK_SIZE, SYNC_FLUSH)

GZIPOutputStream を使用しなかった理由は、それぞれにデータ ブロックが与えられた 4 つのスレッド (変数) があり、各スレッドが独自のブロックを圧縮してから、その圧縮データをグローバル バイト配列に格納したためです。GZIPOutputStream を使用すると、各小さなブロックにヘッダーとトレーラーがあり、それが独自の gzip データであるため、形式が台無しになります (圧縮したいだけです)。

最終的に、すべての圧縮データを保持するこの byteArray である outData を取得しましたが、それをラップする方法がよくわかりません。GZIPOutputStream は圧縮されていないデータをバッファから書き込みますが、この配列はすべて設定されています。すでに圧縮されており、それを形にする方法を見つけようとして壁にぶつかっています。

編集:わかりました、私の側の悪い言葉遣い。必要に応じてリダイレクトできるように、ファイルではなく出力に書き込んでいます。本当に簡単な例は、

cat file.txt | java Jzip | gzip -d | cmp file.txt

0を返す必要があります。現在の問題は、このバイト配列をそのまま出力する場合、それは単なる「生の」圧縮データであることです。gzip には、このすべての追加情報が必要だと思います。

別の方法があれば、それで問題ありません。このような理由は、複数のスレッドを使用する必要があったためです。それ以外の場合は、GZIPOutputStream を呼び出すだけです。

ダブル編集: コメントは多くの優れた洞察を提供するため、別の方法は、もともと 1 つの長いストリームであった圧縮されていないデータのブロックをたくさん持っていることです。gzip が連結されたストリームを読み取ることができる場合、それらのブロックを取得し (そしてそれらを順番に保持し)、それぞれを独自のブロックで GZIPOutputStream を呼び出すスレッドに渡した場合、結果を取得してそれらを連結しました。基本的に、各ブロックにはヘッダー、圧縮された情報、およびトレーラーがあります。それらを連結した場合、gzipはそれを認識しますか?

例:

cat file.txt
Hello world! How are you? I'm ready to set fire to this assignment.

java Testcase < file.txt > file.txt.gz

だから私は入力からそれを受け入れます。プログラム内で、ストリームは「Hello world!」に分割されます。"大丈夫?" 「この割り当てに火をつける準備ができました」 (文字列ではなく、単なるバイトの配列です! これは単なる説明です)

つまり、これら 3 つのバイト ブロックがあり、すべて圧縮されていません。これらの各ブロックをスレッドに渡します。

public static class DGZIPOutputStream extends GZIPOutputStream
{
    public DGZIPOutputStream(OutputStream out, boolean flush) throws IOException
    {
        super(out, flush);
    }
    public void setDictionary(byte[] b)
    {
        def.setDictionary(b);
    }
    public void updateCRC(byte[] input)
    {
        crc.update(input);
    }                       
}

ご覧のとおり、ここではフラッシュを SYNC_FLUSH に設定しただけなので、整列を正しく行い、ディクショナリを設定することができます。各スレッドが DGZIPOutputStream (これはテスト済みで、1 つの長い連続入力に対して機能します) を使用し、これら 3 つのブロック (現在はヘッダーとトレーラーでそれぞれ圧縮されています) を連結すると、 gzip -d file.txt.gz が機能します。 ?

それが奇妙すぎる場合は、辞書を完全に無視してください。それは本当に問題ではありません。途中で追加しただけです。

4

3 に答える 3

6

(sic) コンストラクターnowrapを使用するときに trueを設定すると、結果は生の deflate になります。Deflaterそれ以外の場合は zlib であり、zlib ヘッダーとトレーラーを削除する必要があります。nowrap答えの残りの部分については、本当だと思います。

完全に終了した deflate ストリームを gzip ストリームにラップするには、先頭に 10 バイトを追加する必要があります。

"\x1f\x8b\x08\0\0\0\0\0\0\xff"

(申し訳ありませんが、C 形式です。Java 8 進​​数に変換する必要があります)。また、4 バイトの CRC をリトル エンディアンの順序で追加し、その後に 2^32 を法とする 4 バイトの非圧縮の合計長をこれもリトル エンディアンの順序で追加する必要があります。標準の Java API で何が利用できるかを考えると、CRC をシリアルに計算する必要があります。並行して行うことはできません。 zlibには、並列で計算される個別の CRC を結合する機能がありますが、Java では公開されていません。

完全な、終了したデフレート ストリームと言ったことに注意してください。それらの 1 つを並列の deflate タスクで作成するには、注意が必要です。n-1終了していないデフレート ストリームと 1 つの最終的に終了したデフレート ストリームを作成し、それらを連結する必要があります。最後のものは普通に作られています。もう一方n-1は、バイト境界でそれぞれを終了し、ストリームの終わりとしてマークしないように、同期フラッシュを使用して終了する必要があります。これを行うにはdeflate、 flush パラメータを使用しますSYNC_FLUSH。それらには使用しないでくださいfinish()

より良い圧縮のためsetDictionaryに、各チャンクで前のチャンクの最後の 32K を使用できます。

于 2012-10-28T06:11:06.423 に答える
0

outdataファイルへの書き込みを検討している場合は、次のように記述できます。

GZIPOutputStream outStream= new GZIPOutputStream(new FileOutputStream("fileName"));
outStream.write(outData, 0, outData.length);
outStream.close();

または単にjava.io.FileOutputStream書くために使用します:

FileOutputStream outStream= new FileOutputStream("fileName");
outStream.write(outData, 0, outData.length);
outStream.close();
于 2012-10-28T01:02:30.520 に答える
0

バイト配列を(そのままで)ファイルに書き込みたいだけですか?

ApacheCommonsを使用できます。

FileOutputStream fos = new FileOutputStream("yourFilename");
fos.write(outData);
fos.close():

またはプレーンな古いJava:

BufferedOutputStream bs = null;

try {
    FileOutputStream fs = new FileOutputStream(new File("yourFilename"));
    bs = new BufferedOutputStream(fs);
    bs.write(outData);
    bs.close();

} catch (Exception e) {
    //please handle this
}

if (bs != null) try { 
    bs.close(); 
} catch (Exception e) {
    //please handle this
}
于 2012-10-28T01:02:46.693 に答える