2017-02-15 9 views
1

HTTP PUTで受信した受信データストリームを圧縮するためにjava.util.zip.Deflaterを使用しています。つまり、データを取得します。廊下や裸足で圧縮するのではなく、一気に圧縮する。だから私のHTTPリクエストハンドラを繰り返し、データが入って来て、このように見えるメソッドを呼び出します。 java.util.zip.Deflater.setInputを複数回呼び出すと、何もしません。

byte[] compress(byte[] input) { 
    byte[] output = null; 
    if (this.compressor == null) { 
     this.compressor = new Deflater(Deflater.BEST_COMPRESSION, true); 

     // Add gzip header: 
     output = getGzipHeader(); 
    } 

    this.compressor.setInput(input); 
    this.compressor.finish(); 

    while (!this.compressor.finished()) { 
     byte[] tempOutput = new byte[10240]; 

     int compressedLength = this.compressor.deflate(tempOutput); 

     if (output == null) { 
      output = Arrays.copyOf(tempOutput, compressedLength); 
     } else { 
      byte[] newOutput = Arrays.copyOf(output, output.length + compressedLength); 
      System.arraycopy(tempOutput, 0, newOutput, output.length, compressedLength); 
      output = newOutput; 
     } 
    } 

    // Update CRC: 
    this.crc.update(input); 
    this.byteCount += input.length; 

    return output 
} 

そしてもちろん、このメソッドを含むクラスは、インスタンス変数を持っています

private Deflater compressor; 
private CRC32 crc = new CRC32(); 
private long byteCount = 0; 

、一度最後のバイトがHTTPリクエストから受信された場合、crcbyteCountインスタンス変数からCRCと合計非圧縮長を追加します。

compressメソッドが一度しか呼び出されないため、HTTP PUTで非常に少量のデータを送信する限り、これは素晴らしい結果をもたらします。私は有効なgzipファイルで終わる。私がthis.compressor.setInput(input)を呼び出したにもかかわらず、compressが複数回呼び出されると、すぐに私はcompressが複数回呼び出され、それが機能しません。compressの最初の呼び出し以降、this.compressor.finished()がtrueを返します。新しい入力データすべてのデータが処理された後にthis.compressor.getBytesRead()を見ると、その呼び出しによって返された値は、最初に入力された入力バッファのサイズ(最初の呼び出しはthis.compressor.setInput(input))です。そのメソッドへの以降の呼び出しでは、getBytesRead()によって返される値は増加しません。

setInput()への呼び出し後にfinish()に電話しないと、全く動作しません。出力されません。しかし、finish()Deflaterを受け入れないように電話しているようです。任意入力。

私は間違っていますか?

+1

これは役に立ちます:[DeflaterOutputStream](http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/zip/DeflaterOutputStream.java#119 )? (そして、このクラスを直接使用するのは意味がありますか?) – jtahlborn

+0

jtahlbornとして、DeflaterOutputStreamは大きな助けになると言いました。一般的なコメントとして、配列の操作をすべて自分で行うのではなく、 'ArrayList.addAll(Arrays.asList(tempOutput)) 'を使った方がコードがはるかに単純になります。 –

+0

@jtahlborn、いいえ、私が知る限り、DeflatorOutputStreamを使用する方法はありません。書き込む出力ストリームがないからです。私はおそらく、私のサービスが[Vert.x](http://vertx.io)を使って構築されていると言わざるを得ないので、私は[ReadStream](http://vertx.io/docs/apidocs/index .html?io/vertx/core/streams/ReadStream.html)に書き込んで、[AsyncFile](http://vertx.io/docs/apidocs/index.html?io/vertx/core/file/AsyncFile.html )。データはバイトストリームでReadStreamから受信され、バイトバッファでAsyncFileに書き込まれます。入力ストリームまたは出力ストリームはありません。 –

答えて

0

問題を解決しました。私は基本的にコードをDeflaterOutputStream.write(...)からcompressにコピーし、DeflaterOutputStream.close()から私自身のfinishメソッドにコピーしました。

Deflaterのjavadocでも、ほんの少しを説明した(そして実際にそのjavadocの例のコードに反する)入力を受信し、deflater.setInput(...)を呼び出している間、あなただけ!deflater.needsInput()をチェックすることですされていない、ここでのトリック、および!deflater.finished()ではありません。その後、すべての入力が受信されたら、deflater.finish()に電話し、次にwhile (!deflater.finished())をループして残りのデータを引き続き収縮させて、Deflaterのバッファで保留中の残りのデータを処理します。

詳細については、DeflaterOutputStreamのソースを開き、そのwrite(byte[] b, int off, int len)finish()の方法を見てください。

関連する問題