filterinputstream是字节流装饰器基类,通过继承并重写read方法委托给底层流来扩展功能;filterreader同理用于字符流;需注意委托调用、available()重写、状态同步及关闭逻辑。

Java 中的 FilterInputStream 是字节流的装饰器基类,它本身不直接扩展字符流功能——字符流需用 FilterReader(对应 FilterInputStream 的字符版)。想给流添加新能力(如缓冲、加密、日志、行号统计等),核心思路是继承 FilterInputStream(字节流)或 FilterReader(字符流),重写关键读取方法,并在内部委托给底层流。
FilterInputStream 扩展字节流功能
FilterInputStream 包装一个 InputStream,所有读操作默认转发给它。要扩展功能,需继承它并重写 read()、read(byte[])、read(byte[], int, int) 等方法,在调用父类逻辑前后插入自定义行为。
- 缓冲增强示例:可记录每次读取的字节数,或在读取前检查是否需预加载数据
-
日志/监控示例:在
read()返回前打印已读字节数、耗时或当前偏移量 - 校验/过滤示例:跳过特定字节(如 BOM)、替换控制字符、计算 CRC 校验和
FilterReader 扩展字符流功能
字符流不能直接用 FilterInputStream,必须用 FilterReader(它包装 Reader)。原理一致:继承后重写 read()、read(char[]) 等方法,对字符层面做处理。
- 编码适配:自动识别并跳过 UTF-8 BOM,或统一转为小写再返回
-
行号跟踪:每遇到
'\n'或"\r\n"就递增行号,提供getLineNumber()方法 - 敏感词过滤:读取字符后暂存成字符串片段,匹配并替换关键词(注意避免拆分 Unicode 补充字符)
关键注意事项
装饰器模式依赖“委托+增强”,不是替代。务必调用 super.read(...) 或显式调用被包装流的方法,否则数据无法真正读取。
- 重写
available()时需谨慎——它应反映底层流的可用性,而非装饰后的“逻辑可用” - 若新增状态(如计数器、缓存 buffer),记得在
reset()和mark()/reset()中同步维护 - 关闭流时,通常只需调用
in.close()(FilterInputStream的close()已实现该逻辑)
简单自定义 FilterInputStream 示例
以下是一个统计总读取字节数的装饰器:
public class CountingInputStream extends FilterInputStream {
private long count = 0;
public CountingInputStream(InputStream in) {
super(in);
}
@Override
public int read() throws IOException {
int b = super.read();
if (b != -1) count++;
return b;
}
@Override
public int read(byte[] b) throws IOException {
int n = super.read(b);
if (n > 0) count += n;
return n;
}
public long getCount() { return count; }
}
使用:CountingInputStream cis = new CountingInputStream(new FileInputStream("a.txt")); —— 后续所有读操作都会自动计数。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











