2

標準入力からデータのストリームを取得し、一度に 128 バイト ブロックずつ圧縮してから、標準出力に出力しようとしています。(例: "cat file.txt | java Dict | gzip -d | cmp file.txt"。ここで、file.txt には ASCII 文字が含まれているだけです。)

また、後続の各ブロックに対して、前の 128 バイト ブロックの末尾から取得した 32 バイトの辞書を使用する必要があります。(最初のブロックは、独自の最初の 32 バイトを辞書として使用します。) 辞書をまったく設定しない場合、圧縮は正常に機能します。ただし、ディクショナリを設定すると、gzip でデータを解凍しようとすると、「gzip: stdin: 無効な圧縮データ--crc エラー」というエラーが表示されます。

コードのいくつかの部分を追加/変更しようとしましたが、これまで何も機能せず、Google で解決策を見つけることができませんでした。

私はもう試した...

  • コードの下部にある「def.setDictionary(b)」の前に「def.reset()」を追加しても機能しません。
  • 最初のブロックの後のブロックの辞書を設定するだけでは機能しません。(最初のブロックには辞書を使用しません。)
  • compression.write(input, 0, bytesRead) の前後に「input」配列を指定して updateCRC を呼び出しても機能しません。

何か提案をいただければ幸いです - 私が見逃している、または間違っていることが明らかなことはありますか?

これは私の Dict.java ファイルにあるものです:

import java.io.*;
import java.util.zip.GZIPOutputStream;

public class Dict {
  protected static final int BLOCK_SIZE = 128;
  protected static final int DICT_SIZE = 32;

  public static void main(String[] args) {
    InputStream stdinBytes = System.in;
    byte[] input = new byte[BLOCK_SIZE];
    byte[] dict = new byte[DICT_SIZE];
    int bytesRead = 0;

    try {
        DictGZIPOuputStream compressor = new DictGZIPOuputStream(System.out);
        bytesRead = stdinBytes.read(input, 0, BLOCK_SIZE);
        if (bytesRead >= DICT_SIZE) {
            System.arraycopy(input, 0, dict, 0, DICT_SIZE);
            compressor.setDictionary(dict);
        }

        do {
            compressor.write(input, 0, bytesRead);
            compressor.flush();

            if (bytesRead == BLOCK_SIZE) {
                System.arraycopy(input, BLOCK_SIZE-DICT_SIZE-1, dict, 0, DICT_SIZE);
                compressor.setDictionary(dict);
            }
            bytesRead = stdinBytes.read(input, 0, BLOCK_SIZE);
        } while (bytesRead > 0);

        compressor.finish();
    }
    catch (IOException e) {e.printStackTrace();}
  }

  public static class DictGZIPOuputStream extends GZIPOutputStream {
    public DictGZIPOuputStream(OutputStream out) throws IOException {
        super(out);
    }

    public void setDictionary(byte[] b) {
        def.setDictionary(b);
    }
    public void updateCRC(byte[] input) {
        crc.update(input);
    }
  }
}
4

1 に答える 1

1

内部での zlib アルゴリズムの動作については正確にはわかりませんがDictGZIPOutputStream、書き込み後に write() メソッドを呼び出すと、そのバイト配列の crc が更新されます。したがってupdateCRC()、コードで再度呼び出すと、crc が 2 回更新されるため、問題が発生します。その後、gzip -d が実行されると、前の 2 つの crc 更新の結果として、gzip は「無効な圧縮データ --crc エラー」を訴えます。

また、使用後にコンプレッサーを閉じていないことにも気付きました。上記に貼り付けたコードを実行すると、「gzip: stdin:予期しないファイルの終わり」というエラーが発生しました。そのため、常にメソッドをフラッシュし、最後close メソッドが呼び出されるようにしてください。そうは言っても、私は次のことを持っています、

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.zip.GZIPOutputStream;


public class Dict
{
    protected static final int BLOCK_SIZE = 128;
    protected static final int DICT_DIZE = 32;

    public static void main(String[] args)
    {
        InputStream stdinBytes = System.in;
        byte[] input = new byte[BLOCK_SIZE];
        byte[] dict = new byte[DICT_DIZE];
        int bytesRead = 0;

        try
        {
            DictGZIPOutputStream compressor = new DictGZIPOutputStream(System.out);
            bytesRead = stdinBytes.read(input, 0, BLOCK_SIZE);

            if (bytesRead >= DICT_DIZE)
            {
                System.arraycopy(input, 0, dict, 0, DICT_DIZE);
            }

            do 
            {               
                compressor.write(input, 0, bytesRead);              

                if (bytesRead == BLOCK_SIZE)
                {
                    System.arraycopy(input, BLOCK_SIZE-1, dict, 0, DICT_DIZE);
                    compressor.setDictionary(dict);
                }

                bytesRead = stdinBytes.read(input, 0, BLOCK_SIZE);
            }
            while (bytesRead > 0);
            compressor.flush();         
            compressor.close();
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }

    }

    public static class DictGZIPOutputStream extends GZIPOutputStream
    {

        public DictGZIPOutputStream(OutputStream out) throws IOException
        {
            super(out);
        }

        public void setDictionary(byte[] b)
        {
            def.setDictionary(b);
        }

        public void updateCRC(byte[] input)
        {
            crc.update(input);
        }                       
    }

}

コンソールでのテスト結果。

$ cat file.txt 
hello world, how are you?1e3djw
hello world, how are you?1e3djw adfa asdfas

$ cat file.txt | java Dict | gzip -d | cmp file.txt ; echo $?
0
于 2012-03-20T05:36:56.927 に答える