通过GZIP流读写对象?

3

我是Java的新手,希望学习如何使用GZIPstreams。我已经尝试过以下操作:

ArrayList<SubImage>myObject = new ArrayList<SubImage>(); // SubImage is a Serializable class

ObjectOutputStream compressedOutput = new ObjectOutputStream(
   new BufferedOutputStream(new GZIPOutputStream(new FileOutputStream(
   new File("....")))));
compressedOutput.writeObject(myObject);

并且

ObjectInputStream compressedInput = new ObjectInputStream(
   new BufferedInputStream(new GZIPInputStream(new FileInputStream(
   new File("....")))));
myObject=(ArrayList<SubImage>)compressedInput.readObject();

当程序将myObject写入文件时没有抛出任何异常,但当它到达以下行时:
myObject=(ArrayList<SubImage>)compressedInput.readObject();

它抛出了这个异常:

Exception in thread "main" java.io.EOFException: Unexpected end of ZLIB input stream

我该如何解决这个问题?

3
你关掉了输出流吗? - Thilo
1个回答

7
你需要刷新和关闭输出流,否则至少BufferedOutputStream不会将所有内容写入文件(它会分块写入以避免影响性能)。如果调用compressedOutput.flush()compressedOutput.close()即可。你可以尝试编写一个简单的字符串对象并检查文件是否正确编写。如何操作呢?如果你编写了一个xxx.txt.gz文件,可以使用你喜欢的zip应用程序打开它,并查看xxx.txt。如果应用程序出现问题,则表示内容未完全编写。

对评论的扩展回答:进一步压缩数据

更改序列化

如果SubImage是你自己的对象,你可以更改其标准序列化。查看java.io.Serializable javadoc以了解如何执行此操作。这很简单。

仅编写所需内容

序列化的缺点在于需要在编写每个实例之前写“这是一个SubImage”。如果您事先知道即将出现的内容,则不必这样做。因此,您可以尝试更加手动地序列化它。
为了编写您的列表,而不是编写对象,请直接编写符合列表要求的值。您只需要一个DataOutputStream(但ObjectOutputStream是DOS,因此您仍然可以使用它)。
dos.writeInt(yourList.size()); // tell how many items
for (SubImage si: yourList) {
   // write every field, in order (this should be a method called writeSubImage :)
   dos.writeInt(...);
   dos.writeInt(...);
   ...
}

// to read the thing just:
int size = dis.readInt();
for (int i=0; i<size; i++) {
   // read every field, in the same order (this should be a method called readSubImage :)
   dis.readInt(...);
   dis.readInt(...);
   ...
   // create the subimage
   // add it to the list you are recreating
}

这种方法更加手动,但如果:
  1. 你知道将要编写什么
  2. 你不需要针对多个类型进行序列化
它的效果相当可观,而且明显比Serializable更压缩。
请注意,还有替代框架用于序列化对象或创建字符串消息(例如,XStream用于xml,Google Protocol Buffers用于二进制消息等)。这些框架可以直接工作到二进制或编写一个字符串,然后再编写。
如果您的应用程序需要更多信息,或者只是好奇,也许您应该看看它们。 替代序列化框架 在SO中查找并发现了几个问题(和答案)解决了这个问题。

https://stackoverflow.com/search?q=alternative+serialization+frameworks+java

我发现XStream非常容易且直观地使用。而JSON是一种相当易读且简洁的格式(并且与Javascript兼容,这可能是一个优点:)。

我应该选择:

Object -> JSON -> OutputStreamWriter(UTF-8) -> GZippedOutputStream -> FileOutputStream

哇,它完美地运行了!感谢您的帮助。我完全忘记了 BufferedOutputStream 对象在创建后应该被刷新。 - Jisan Mahmud
有没有办法更压缩SubImage对象?该类具有4个整数和一个整数数组作为实例变量。 - Jisan Mahmud
我已经在帖子中添加了我的留言。希望能有所帮助! - helios

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接