java io filter链按数据流向逐层包装原始流,解包顺序须与封装顺序相反,如读取test.gz.aes需bufferedinputstream→gzipinputstream→cipherinputstream→fileinputstream,写入则镜像反转;所有filter均继承filterinputstream,支持统一inputstream引用和自动委托调用。

Java IO 流中通过 Filter 链组合加密、压缩与缓冲,核心不是“堆类”,而是按数据流向**逐层包装原始流**——底层是真实数据源(如文件),上层是功能装饰器,每加一层就增强一种能力,且顺序必须符合实际处理逻辑。
功能叠加必须遵循数据流向逻辑
比如读取一个 test.gz.aes 文件(先 AES 加密、再 GZIP 压缩、最后存为文件),解包流程就得反着来:先解密 → 再解压 → 最后缓冲读取。对应 Filter 链的构造顺序也必须是:
-
最内层:原始数据源(
FileInputStream) -
中间层:解密流(
CipherInputStream)→ 解密密文得到压缩字节 -
再外层:解压流(
GZIPInputStream)→ 解压得到明文字节 -
最外层:缓冲流(
BufferedInputStream)→ 提升读取效率
代码写法自然就是嵌套构造:
Java JDK 25 来自 OpenJDK 官方归档,版本为 JDK 25,本条下载地址已指向官方 Windows x64 zip 安装包直链,适合调试旧项目或兼容旧版 Java 运行环境。
new GZIPInputStream(
new CipherInputStream(
new FileInputStream("test.gz.aes"), cipher)
)
);
每个 Filter 都是 InputStream 的子类型,接口完全兼容
所有 Filter 类(BufferedInputStream、GZIPInputStream、CipherInputStream)都继承自 FilterInputStream,而后者本身是 InputStream 的子类。这意味着:
- 你始终可以用
InputStream类型变量引用整个链,无需关心内部几层 - 调用
read()、available()等方法时,请求会自动穿透各层,按包装顺序依次处理 - 关闭最外层流(
in.close())会自动触发整个链的资源释放(前提是各 Filter 正确委托了close())
写入场景同理,但顺序要镜像反转
如果要写入并同时加密、压缩、缓冲,顺序就得反过来:先缓冲 → 再压缩 → 最后加密 → 写入文件。因为数据从内存出发,流向是「应用 → 缓冲 → 压缩 → 加密 → 文件」:
OutputStream out = new CipherOutputStream(new GZIPOutputStream(
new BufferedOutputStream(
new FileOutputStream("out.gz.aes")
),
),
cipher
);
注意:GZIPOutputStream 和 CipherOutputStream 都要求在关闭前调用 finish() 或依赖 close() 自动完成收尾(如 GZIP 需写入校验和,AES 可能需填充补位)。
避免常见陷阱
-
顺序错乱:比如把
BufferedInputStream放在GZIPInputStream外层,会导致缓冲的是已解压的大数据,浪费内存;放在内层又无法加速解压过程 - 资源未关闭:只关最外层即可,但务必用 try-with-resources,确保异常时也能释放
-
编码/字符问题混入字节流:Filter 链处理的是原始字节,加密压缩都基于 byte。若需文本处理(如 UTF-8),应在链之外用
InputStreamReader转换,不要试图用FilterReader混搭 -
自定义 Filter 必须正确委托:继承
FilterInputStream时,所有方法(尤其是read、skip、available、close)都应显式调用in.xxx(),否则功能中断
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










