Я использую java.util.zip.Deflater для сжатия входящего потока данных, полученных через HTTP PUT, что означает, что я получаю данные быть сжатым в дрибах и драпировках, причем не все одновременно. Так что мой 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-запроса, я добавляю CRC и полную несжатую длину из переменных экземпляра crc
и byteCount
.
Пока я посылаю очень небольшое количество данных в HTTP PUT, это отлично работает, потому что метод compress
вызван только один раз. Я получаю действительный файл gzip. Как только я отправляю более нескольких сотен байтов, в результате чего вызов вызываются более одного раза, он не работает, потому что при всех последующих вызовах compress
после первого, this.compressor.finished()
возвращает true, хотя я вызвал this.compressor.setInput(input)
с новые входные данные. Если я просмотрю this.compressor.getBytesRead()
после того, как все данные обработаны, значение, возвращаемое этим вызовом, будет точно размером первого входного буфера, который пришел (первый вызов this.compressor.setInput(input)
). Ни один из последующих вызовов этого метода не увеличивает значение, возвращаемое getBytesRead()
.
Если я не звоню finish()
после звонка на setInput()
, он вообще не работает - я не получаю никакого вывода. Но похоже, что звонок finish()
говорит Deflater
не принимать любой больше ввода.
Что я делаю неправильно?
это помогает: [DeflaterOutputStream] (http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/zip/DeflaterOutputStream.java#119)? (и было бы целесообразно просто использовать этот класс напрямую?) – jtahlborn
Как сказал jtahlborn, DeflaterOutputStream очень поможет. Как общий комментарий, ваш код выглядел бы намного проще, если бы вы использовали 'ArrayList.addAll (Arrays.asList (tempOutput)) вместо того, чтобы делать все это манипулирование массивом самостоятельно. –
@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 в байтовых буферах. Нет входных или выходных потоков. –