Java IO 中的 Filter 模式(装饰器模式)通过层层包裹基础流(如 FileInputStream),为 I/O 操作提供灵活的功能扩展。核心类 FilterInputStream/FilterOutputStream 作为抽象装饰器,其子类(如 BufferedInputStream, DataInputStream)在不改变原始流结构的前提下,动态添加缓冲、数据类型处理、行读取等增强功能。该模式解耦了基础 I/O 与扩展功能,支持功能组合(如先缓冲再转换),显著提升代码复用性与可维护性。本文剖析其运作机制,并演示如何自定义 FilterOutputStream 实现字母转大写,揭示其作为 Java I/O 灵活扩展基石的核心价值。


一、为何需要 Filter 模式?

基础流(如 FileInputStream, FileOutputStream)仅提供字节读写能力。现实需求往往更复杂:

  • 缓冲加速BufferedInputStream
  • 读写基本数据类型DataInputStream
  • 按行处理文本BufferedReader

直接修改基础流类会破坏开闭原则。Filter 模式应运而生 —— 装饰器模式(Decorator Pattern) 的经典应用。

二、Filter 模式核心机制

  1. 抽象装饰器: FilterInputStreamFilterOutputStream
    • 内部持有一个被装饰的底层流对象 (protected InputStream in; / protected OutputStream out;)。
    • 继承自 InputStream/OutputStream重写关键方法(如 read(), write()),默认将调用委托给持有的底层流
  1. 具体装饰器: 继承自 FilterXXXStream
    • 在委托调用前后过程中加入增强逻辑。
    • 例如 BufferedInputStream.read() 先检查内部缓冲区,为空时从底层流读取一大块数据填充缓冲区。
// FilterInputStream 关键源码示意
public class FilterInputStream extends InputStream {
    protected volatile InputStream in; // 核心:持有被装饰的流
    protected FilterInputStream(InputStream in) { this.in = in; }
    public int read() throws IOException { return in.read(); } // 默认委托
    // ... 其他方法类似委托
}
  1. 灵活组合:多层嵌套装饰器。
// 组合:文件流 -> 缓冲流 -> 数据流 (读int/double等)
DataInputStream dis = new DataInputStream(
                        new BufferedInputStream(
                            new FileInputStream("data.bin")));
int num = dis.readInt(); // 高效读取int

三、实战:自定义大写转换过滤器

import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;

/**
 * 自定义 FilterOutputStream:将写入的英文字母转换为大写
 */
public class UpperCaseFilterOutputStream extends FilterOutputStream {

    public UpperCaseFilterOutputStream(OutputStream out) {
        super(out); // 调用父类构造,传入被装饰的底层流
    }

    // 核心增强:重写write(int),在写入前转换字符
    @Override
    public void write(int b) throws IOException {
        // 只转换小写字母 (a-z), 其他字符原样写入
        if (b >= 'a' && b <= 'z') {
            b = b - ('a' - 'A'); // 转换为大写 ASCII 码
        }
        super.write(b); // 委托给持有的底层流执行实际写入
    }

    // 重写write(byte[], int, int) 提升批量写入效率
    @Override
    public void write(byte[] b, int off, int len) throws IOException {
        for (int i = off; i < off + len; i++) {
            write(b[i]); // 复用我们增强的write(int)方法
        }
    }
}

使用示例:

import java.io.FileOutputStream;
import java.io.IOException;

public class FilterDemo {
    public static void main(String[] args) {
        // 组合:文件流 -> 自定义大写过滤器
        try (OutputStream fos = new FileOutputStream("output.txt");
             UpperCaseFilterOutputStream ucos = new UpperCaseFilterOutputStream(fos)) {

            String text = "Hello, Filter World! 123\n";
            byte[] bytes = text.getBytes();
            ucos.write(bytes); // 写入时自动转大写

            System.out.println("数据已写入并转换!");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

运行结果 (output.txt 内容):

HELLO, FILTER WORLD! 123

四、关键优势与注意事项

  1. 优势:
    • 开闭原则: 不修改基础流即可扩展功能。
    • 灵活组合: 按需叠加功能(缓冲+加解密+压缩)。
    • 职责清晰: 每个装饰器只负责单一增强。
    • 透明性: 使用方式与基础流一致 (read/write)。
  1. 注意:
    • 装饰顺序: 顺序可能影响结果和性能(如缓冲应靠近底层流)。
    • 资源关闭: 关闭最外层流会自动关闭所有内嵌流(通常无需手动关闭内部流)。
    • NIO.2 补充: Java NIO 的 Channel 和 Buffer 提供了更高性能的替代方案,但装饰器模式在传统 IO 和流式 API 中仍广泛应用。

结语: Filter 模式是 Java I/O 灵活性的核心支柱。理解其装饰器本质(FilterXXXStream + 委托 + 功能增强)和组合威力,是掌握高效、可扩展流处理的关键。自定义过滤器(如本文的 UpperCaseFilterOutputStream)将基础 I/O 变成了可插拔的功能管道 —— 你的代码,就是最好的插件

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐