2013-04-01 3 views
8

Я хочу сжать некоторые данные, поэтому я наткнулся на классы DeflatorInputStream & DeflatorOutputStream. Однако следующий пример показывает, что я не могу восстановить исходные данные при использовании этих классов.DeflatorInputStream и DeflatorOutputStream не восстанавливают исходные данные

Когда я переключаюсь на ZipInputStream и ZipOutputStream, он работает, но поскольку мне не нужны файлы zip как таковые, я думал, что общее сжатие будет лучше. В основном меня интересует, почему этот пример не работает.

//Create some "random" data 
int bytesLength = 1024; 
byte[] bytes = new byte[bytesLength]; 
for(int i = 0; i < bytesLength; i++) { 
    bytes[i] = (byte) (i % 10); 
} 

//Compress the data, and write it to somewhere (a byte array for this example) 
ByteArrayOutputStream arrayOutputStream = new ByteArrayOutputStream(); 
DeflaterOutputStream outputStream = new DeflaterOutputStream(arrayOutputStream); 
outputStream.write(bytes); 

//Read and decompress the data 
byte[] readBuffer = new byte[5000]; 
ByteArrayInputStream arrayInputStream = new ByteArrayInputStream(arrayOutputStream.toByteArray()); 
DeflaterInputStream inputStream = new DeflaterInputStream(arrayInputStream); 
int read = inputStream.read(readBuffer); 

//Should hold the original (reconstructed) data 
byte[] actuallyRead = Arrays.copyOf(readBuffer, read); 

//Results differ - will print false 
System.out.println(Arrays.equals(bytes, actuallyRead)); 

ответ

13

Обвинение в историческом прецеденте. В Unix функция, используемая для изменения deflate, называется inflate. Таким образом, в отличие от других классов Java IO, пара входных и выходных потоков не имеет (явно) совпадающих имен.

DeflaterOutputStream фактически не позволяет вам отменить дефляцию, вместо этого он дефлирует байты, когда они передаются ему из раковины в источник. DeflaterInputStream также сдувает, но выполняет свое действие как потоки данных от источника к раковине.

Для того, чтобы прочитать данные в несжатом (завышены) формате, необходимо использовать InflaterInputStream:

InflaterInputStream inputStream = new InflaterInputStream(arrayInputStream); 

Кроме того, потому что его можно не получить все сжатые данные из потока в одном read вызова, вам нужно использовать цикл. Что-то вроде этого:

int read; 
byte[] finalBuf = new byte[0], swapBuf; 
byte[] readBuffer = new byte[5012]; 

ByteArrayInputStream arrayInputStream = new ByteArrayInputStream(
     compressed); 
InflaterInputStream inputStream = new InflaterInputStream(
     arrayInputStream); 
while ((read = inputStream.read(readBuffer)) != -1) { 
    System.out.println("Intermediate read: " + read); 
    swapBuf = finalBuf; 
    finalBuf = new byte[swapBuf.length + read]; 
    System.arraycopy(swapBuf, 0, finalBuf, 0, swapBuf.length); 
    System.arraycopy(readBuffer, 0, finalBuf, swapBuf.length, read); 
} 

Наконец, убедитесь, что либо промойте выходной поток Deflater до извлечения сжатых байтов (или альтернативно закрыть поток).

1

Есть только 2 небольших изменения, которые заставляют ваш код работать.

//Compress the data, and write it to somewhere (a byte array for this example) 
ByteArrayOutputStream arrayOutputStream = new ByteArrayOutputStream(); 
DeflaterOutputStream outputStream = new DeflaterOutputStream(arrayOutputStream); 
outputStream.write(bytes); 
outputStream.close(); 

Во-первых, вы должны закрытия() выходной поток. Дефлятор должен сделать некоторые заключительные шаги, чтобы завершить свою работу.

InflaterInputStream inputStream = new InflaterInputStream(arrayInputStream); 

Если вы используете дефлятор InputStream, вы снова сжать сжатые данные. Замените его на Inflator InputStream, и ваш код будет работать нормально.