java 对象序列化中 gzip 压缩序列化的实现,核心在于将对象字节流通过 gzipoutputstream 进行压缩后写入文件,读取时再通过 gzipinputstream 解压并反序列化。具体做法是构建一个包含 objectoutputstream 和 gzipoutputstream 的嵌套输出流链,或者使用 bytearrayoutputstream 作为中间缓冲,先完成序列化再压缩。这样做可以显著减小存储体积,但会牺牲一定的 cpu 计算时间。

如何编写完整的 GZIP 序列化与反序列化工具类
要实现这一功能,需要创建一个工具类,分别提供 serialize() 和 deserialize() 方法。在序列化时,我们通常推荐使用内存缓冲的方式,即先将对象序列化为字节数组,再将该数组压缩为 GZIP 格式;反序列化则是逆向过程,先解压 GZIP 数据,再将其还原为对象。这种方法比直接操作文件流更灵活,便于后续的网络传输或缓存处理。

import java.io.*;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
public class GZipSerializer {
public static byte[] serialize(Object obj) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try (GZIPOutputStream gzos = new GZIPOutputStream(baos)) {
ObjectOutputStream oos = new ObjectOutputStream(gzos);
oos.writeObject(obj);
}
return baos.toByteArray();
}
public static Object deserialize(byte[] data) throws IOException, ClassNotFoundException {
ByteArrayInputStream bais = new ByteArrayInputStream(data);
try (GZIPInputStream gzis = new GZIPInputStream(bais)) {
ObjectInputStream ois = new ObjectInputStream(gzis);
return ois.readObject();
}
}
}
上述代码展示了最标准的实现方式。注意 try-with-resources 的使用确保了流的正确关闭。在实际使用中,调用 serialize() 传入任意实现了 Serializable 接口的对象,即可得到压缩后的字节数组。例如,对于一个包含大量字符串数据的 User 对象,序列化后的体积通常会比未压缩的 ObjectOutputStream 输出小很多。
为什么推荐先序列化到内存再压缩,而不是直接写文件?
直接写文件的方案虽然可行,但在实际工程中存在一些隐患。如果直接将 GZIPOutputStream 包裹在 FileOutputStream 上,一旦序列化过程中抛出异常(如对象引用了不可序列化的字段),可能导致生成的 GZIP 文件损坏或不完整,且难以恢复。而采用内存缓冲策略,可以在压缩前确保整个对象图已经完整序列化,从而保证数据的原子性。

// 对比:直接写文件的潜在风险代码
public static void serializeToFileDirect(Object obj, File file) throws IOException {
try (GZIPOutputStream gzos = new GZIPOutputStream(new FileOutputStream(file))) {
ObjectOutputStream oos = new ObjectOutputStream(gzos);
oos.writeObject(obj); // 如果这里失败,file 可能已存在但不完整
}
}
从图中可以看出,内存缓冲模式在序列化阶段和压缩阶段之间有一个明确的边界。这种分离使得我们可以对序列化结果进行校验、日志记录或重试,而不会污染最终的存储介质。此外,内存缓冲也允许我们在压缩前后对数据进行额外的处理,比如加密或添加元数据头,这在分布式系统中非常常见。
当序列化对象中包含 transient 关键字修饰的字段时,GZIP 压缩会有什么影响?
transient 关键字的作用是告诉 Java 序列化机制忽略该字段,不将其写入字节流。这一行为发生在序列化阶段,早于 GZIP 压缩阶段。因此,GZIP 压缩不会对 transient 字段的处理产生任何额外影响,它只是忠实地压缩了序列化机制输出的字节内容。这意味着,被标记为 transient 的字段不仅不会被保存,也不会占用压缩后的存储空间。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











