我正在尝试读取通过gziping对象创建的字节数组的内容,但是当我尝试解压缩字节数组的内容时,出现错误,指出:java.io.EOFException:ZLIB输入流的意外结束< / p>
我正在尝试使用Java的try-with-resources惯用法来压缩和解压缩对象时管理流资源,但是,如果我将ByteArrayOutputStream添加到try-with-resources块中,则另一个流ObjectOutputStream无法关闭。
我检查了ByteArrayOutputStream的实现,该实现扩展了AutoCloseable接口,即使它的关闭未执行任何工作,它也不应干扰其他资源的关闭。
我尝试压缩对象的代码:
//This fails
public static byte[] returnCompressedObject(Object object) {
try(ByteArrayOutputStream out = new ByteArrayOutputStream();
GZIPOutputStream gzOut = new GZIPOutputStream(out);
ObjectOutputStream objOut = new ObjectOutputStream(gzOut)) {
objOut.writeObject(object);
return out.toByteArray();
} catch (IOException e) {
throw new RuntimeException("Error converting object to bytes ", e);
}
}
//This works with ByteArrayOutputStream moved out of try-with-resources block
public static byte[] returnCompressedObjectWithByteArrayOutside(Object object) {
//ByteArrayOutputStream moved out of try-with-resources block
ByteArrayOutputStream out = new ByteArrayOutputStream();
try(GZIPOutputStream gzOut = new GZIPOutputStream(out);
ObjectOutputStream objOut = new ObjectOutputStream(gzOut)) {
objOut.writeObject(object);
} catch (IOException e) {
throw new RuntimeException("Error converting object to bytes ", e);
}
return out.toByteArray();
}
//This works with explicit close being called on ObjectOutputStream
public static byte[] returnCompressedObjectWithExplicitClose(Object object) {
try(ByteArrayOutputStream out = new ByteArrayOutputStream();
GZIPOutputStream gzOut = new GZIPOutputStream(out);
ObjectOutputStream objOut = new ObjectOutputStream(gzOut)) {
objOut.writeObject(object);
//Explicit close being called on ObjectOutputStream
objOut.close();
return out.toByteArray();
} catch (IOException e) {
throw new RuntimeException("Error converting object to bytes ", e);
}
}
在这些 returnCompressedObjectWithByteArrayOutside 和 returnCompressedObjectWithExplicitClose 中,似乎返回了一个我可以在以下unzip方法中使用的字节数组,但是使用了 returnCompressedObject 解压缩结束前引发异常 java.io.EOFException:解压缩期间ZLIB输入流的意外结束 用于解压缩的方法:
public static String decompressUsingGZip(byte[] object) {
try(ByteArrayInputStream messageInputStream = new ByteArrayInputStream(object);
GZIPInputStream gzipStream = new GZIPInputStream(messageInputStream);
InputStreamReader inputStreamReader = new InputStreamReader(gzipStream, StandardCharsets.UTF_8);
BufferedReader reader = new BufferedReader(inputStreamReader)){
return reader.lines().collect(Collectors.joining());
} catch (IOException e) {
throw new RuntimeException("Error uncompressing object", e);
}
}
我试图理解为什么 returnCompressedObject 的行为不正常,并关闭流。
在搜索文档时,我没有发现任何地方提到我们不应该在try-with-resources中使用ByteArrayOutputStream。
我们将帮助您理解这种行为的原因。
答案 0 :(得分:1)
我试图了解为什么returnCompressedObject不是 保持应有的状态并关闭流。
它失败,因为GZIPOutputStream
有内部缓冲区,没有刷新。通过关闭它,您将强制流执行任何最终操作并写出所有剩余字节。如果不关闭它,将会丢失一些数据,因此会丢失Unexpected end of ZLIB input stream
消息。
答案 1 :(得分:1)
将OutputStream转换为byteArray时,它期望将其关闭。 在第3种情况下,您将在调用 out.toByteArray()之前显式关闭 ObjectOutputStream ,这完全有意义。 在第二种情况下,您已经将 out.toByteArray()移到了try-catch之外,并在try-with-resource块中定义了 ObjectOutputStream ,当try块结束时,它将关闭ObjectOutputStream。因此,当您调用out.toByteArray()时,ObjectOutputStream已关闭,因此不会再出现问题。
我仍然建议您采用第三种方法,或将整个代码包装在另一个try-catch块中,并在try-with-resource块中定义ByteArrayOutputStream。这样蒸汽就可以在返回时关闭。