Java IO流之FilterInputStream和FilterOutputStream分析

简介

FilterInputStream和FilteOutputStream分别是过滤输入流和过滤输出流,他们的作用是为基础流提供一些额外的功能.拿FilterInputStream来说,常见的子类有DataInputStream,BufferedInputStream以及PushBackInputStream等.其子类总结为:

  1. DataInputStream.数据输入流,以机器无关的方式读取Java的基本类型.
  2. BufferedInputStream缓冲输入流,由于基础输入流一个字节一个字节读取,频繁与磁盘进行交互,造成读取速度较低.缓冲流的存在就是先将数据读取到缓冲流(内存中),然后一次性从内存中读取多个字符.提高读取的效率.
  3. PushInputStream回退输入流,java中读取数据的方式是顺序读取,如果某个数据不需要读取,需要程序处理.PushBackInputStream就可以将某些不需要的数据回退到缓冲中.

FilterInputStream所有的子类都是为基础流输入提供了一些额外的功能,为什么不直接继承基础流,将基础流中的方法直进行"装饰".这里要说到一个装饰者模式和继承的区别.

装饰者模式和继承

装饰者模式,就是将原有的基础流进行"装饰",那么装饰后的方法要与原先被装饰的基础类要保持一致,也可以在对基础流进行扩展.而继承是继承父类的属性和方法,通过重写父类里面的方法也可以起到"装饰"作用.比如强化或者优化父类里面的一些方法.两者的区别是装饰者模式可以动态地扩展一个对象.给对象添加额外的功能.而且装饰者和被装饰者之间不会产生耦合.

先看一下继承,例如要实现DataInputStream的功能,我们需要继承每个基础输入流,而且基础输入流不仅仅是图中这些,还有FileInputStream所有子类以及InputStream子类等等类,都需要继承,那么这些类就会爆炸式的增长.而且类之间耦合性特别高.如果使用继承,那么IO流系统何其庞大.

那么装饰者模式存在意义就在此处,相比继承,没有这么多繁杂的类,而且类与类的之间的耦合性降低,具体做法就是将提出一个类FilterInputStream.而其子类就是各个功能的实现类.如果想要基础输入流要某个功能,那么就可以将对应的基础输入流传到对应的子类构造方法中.代码也是来源于生活,这个装饰者模式跟生活中很多实例相似,比如每家有可乐,要想喝冰可乐,怎么办.不是每家去买一个冰箱,而是大家凑钱买一个公共的冰箱,然后要想喝冰颗可乐,就直接放在公共的冰箱里面,就实现了"冰"这个功能(好吧这个例子有点牵强)

案例:现在要将FileInputStream实现一个功能,读取与机器无关的java类中Int类型.就可以直接将FileInputStream传入DataInputStream的有参构造方法中

代码如下:

public class FilterDemo {
 public static void main(String[] args) throws Exception{
   DataOutputStream dos = new DataOutputStream(new FileOutputStream("D:\\java.txt"));
   dos.writeInt(1234567);
   DataInputStream dis = new DataInputStream(new FileInputStream("D:\\java.txt"));
   System.out.println(dis.readInt());
   dis.close();
   dos.close();
 }
}

运行结果:

1234567

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();
    }
    
    //从输入流读取数据到字节数组b中
    public int read(byte b[]) throws IOException {
        return read(b, 0, b.length);
    }
    
    //从输入流中读取数据到b的off位置开始,len个字节.
    public int read(byte b[], int off, int len) throws IOException {
        return in.read(b, off, len);
    }
    
    //跳过n个字节
    public long skip(long n) throws IOException {
        return in.skip(n);
    }
    
    //从输入流中可读取的剩余字节数
    public int available() throws IOException {
        return in.available();
    }

    public void close() throws IOException {
        in.close();
    }
    
    //在输入流当前标记
    public synchronized void mark(int readlimit) {
        in.mark(readlimit);
    }

    //将当前位置重置到标记的位置
    public synchronized void reset() throws IOException {
        in.reset();
    }
    
    //测试输入流是否支持标记
    public boolean markSupported() {
        return in.markSupported();
    }
}

FilterOutputStream源码分析

public class FilterOutputStream extends OutputStream {

    protected OutputStream out;
    
    //有参构造方法,传入基础输出流
    public FilterOutputStream(OutputStream out) {
        this.out = out;
    }
    
    //将b写到输出流
    public void write(int b) throws IOException {
        out.write(b);
    }
    
    //将字节数组b写到输出流中
    public void write(byte b[]) throws IOException {
        write(b, 0, b.length);
    }
    
    //将字节数组b中off开始,len个字节写到输出流中
    public void write(byte b[], int off, int len) throws IOException {
        if ((off | len | (b.length - (len + off)) | (off + len)) < 0)
            throw new IndexOutOfBoundsException();

        for (int i = 0 ; i < len ; i++) {
            write(b[off + i]);
        }
    }
    
    //刷新输出流
    public void flush() throws IOException {
        out.flush();
    }

    //刷新输出流,强制将已写入缓冲的流写出
    @SuppressWarnings("try")
    public void close() throws IOException {
        try (OutputStream ostream = out) {
            flush();
        }
    }
}

 

  • 22
    点赞
  • 56
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值