413. Java 文件操作基础 - 用装饰器模式实现 Sonnet 的 GZIP 序列化
✍️ 写入压缩的单个 Sonnet
各位,我们已经能够把 Sonnet 从文本文件中读出来了,那么接下来要做的事情是:把一个 Sonnet 压缩存储。
为什么要压缩呢?💡
- 因为 原始文本文件可能很大(莎士比亚的十四行诗全集有
154首),如果我们以后要存储、传输,压缩可以大大节省空间。 - Java 提供了内置的
GZIP压缩工具类,我们不需要自己写压缩算法,只要用好API就可以了。
🎯 压缩思路
我们希望把一个 Sonnet 的所有行写入一个压缩后的二进制文件。Java 的 I/O 提供了一个 GZIPOutputStream 类来帮我们完成压缩。
具体思路:
- 创建一个
ByteArrayOutputStream—— 用来存放最终压缩后的二进制数据。 - 用
GZIPOutputStream包装它 —— 实现压缩功能。 - 再用
PrintWriter包装 —— 方便逐行写入字符串(因为PrintWriter提供println()方法,非常适合写文本)。 - 最终返回一个
byte[]—— 就是压缩后的字节数组,可以保存到文件或传输给别人。
✅ 在 Sonnet 类中新增方法
class Sonnet {
private List<String> lines = new ArrayList<>();
public void add(String line) {
lines.add(line);
}
// 压缩成字节数组的方法
byte[] getCompressedBytes() throws IOException {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try (GZIPOutputStream gzos = new GZIPOutputStream(bos);
PrintWriter printWriter = new PrintWriter(gzos)) {
for (String line : lines) {
printWriter.println(line);
}
}
// 返回压缩后的字节数组
return bos.toByteArray();
}
}
🔍 方法解析
-
ByteArrayOutputStream bos
→ 相当于一个“内存文件”,所有压缩数据最终都在这里。 -
GZIPOutputStream gzos = new GZIPOutputStream(bos)
→ 把数据写进去时会自动压缩。 -
PrintWriter printWriter = new PrintWriter(gzos)
→ 提供println(line)方法,写起来很方便。 -
try-with-resources
→ 即使这里没有外部文件,依然有必要:它能自动调用close(),帮我们刷新(flush)缓冲区,确保所有内容都被写入压缩流。
📌 使用示例
假设我们有一个 Sonnet 对象:
public class Main {
public static void main(String[] args) throws IOException {
Sonnet sonnet = new Sonnet();
sonnet.add("Shall I compare thee to a summer's day?");
sonnet.add("Thou art more lovely and more temperate:");
sonnet.add("Rough winds do shake the darling buds of May,");
sonnet.add("And summer's lease hath all too short a date:");
// 获取压缩后的字节数组
byte[] compressed = sonnet.getCompressedBytes();
// 写入文件
Files.write(Path.of("sonnet1.gz"), compressed);
System.out.println("✅ Sonnet 已压缩并写入 sonnet1.gz 文件");
}
}
运行结果:
- 在项目目录下会生成一个
sonnet1.gz文件。 - 你可以用
gzip -d sonnet1.gz(Linux/Mac)或 7-Zip(Windows)解压缩,里面就是你写的那几行诗。
🚀 总结
- 压缩文件存储在字节数组中,方便后续操作(写入文件/网络传输)。
-
装饰器模式:
ByteArrayOutputStream → GZIPOutputStream → PrintWriter,逐层增加功能。 - try-with-resources 不仅用于外部文件资源,也能确保缓冲区正确刷新。