DeflatorInputStream and DeflatorOutputStream do not reconstruct the original data

风格不统一 提交于 2019-11-29 18:39:52

问题


I want to compress some data, so I came across the DeflatorInputStream & DeflatorOutputStream classes. However, the following example shows that I can't seem to reconstruct my original data when using these classes.

When I switch to a ZipInputStream and ZipOutputStream it does work, but since I don't need zip files per se, I thought a generic compression would be better. Mainly I'm interested in understanding why this example doesn't work.

//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));

回答1:


Blame historical precedent. On Unix, the function used to reverse a deflate is called inflate. So, unlike alot of other Java IO classes, the input and output stream pair does not have (obviously) matching names.

The DeflaterOutputStream doesn't actually allow you to reverse a deflation, instead it deflates bytes as they are passed to it from a sink to a source. DeflaterInputStream also deflates, but it performs its action as data flows from the source to the sink.

In order to read your data in uncompressed (inflated) format, you need to use an InflaterInputStream:

InflaterInputStream inputStream = new InflaterInputStream(arrayInputStream);

Also, because its possible to not get all compressed data from the stream in one read call, you need to use a loop. Something like this:

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);
}

Finally, make sure to either flush your deflater output stream prior to retrieving the compressed bytes (or alternatively close the stream).




回答2:


There are only 2 little changes that make your code work.

//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();

First, you have to close() the output stream. The deflator has to make some final steps to complete his work.

InflaterInputStream inputStream = new InflaterInputStream(arrayInputStream);

If you use a Deflator InputStream, you compress the compressed data again. Replace it with an Inflator InputStream and your code will work fine.



来源:https://stackoverflow.com/questions/15742087/deflatorinputstream-and-deflatoroutputstream-do-not-reconstruct-the-original-dat

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!