Java IO流以及装饰器模式在其上的运用

流概述

Java中,流是一种有序的字节序列,可以有任意的长度。从应用流向目的地称为输出流,从目的地流向应用称为输入流。

Java的流族谱

Java的 java.io 包中囊括了整个流的家族,输出流和输入流的谱系如下所示:

InputStream和OutputStream

InputStream和OutputStream分别是输入输出流的顶级抽象父类,只定义了一些抽象方法供子类实现。

在输出流OutputStream中,如果你需要向一个输出流写入数据,可以调用 void write(int b) 方法,这个方法会将b的低八位写入流中,高24位将会被自动忽略。如果想要批量写入数据呢,那么可以调用 void write(byte[] b) 方法将一个字节数组的内容全部写入流中,同时还有 void write(byte[] b, int off, int len) 可以让你指定从哪里写入多少数据。

如果你希望你向流中写入的数据能够尽快地输送到目的地,比如说文件,那么可以在写入数据后,调用 flush() 方法将当前输出流刷到操作系统层面的缓冲区中。不过需要注意的是,此方法并不保证数据立马就能刷到实际的物理目的地(比如说存储)。

使用完流后应该调用其 close() 方法将流关闭,流关闭时,将会先flush,后关闭。

在输入流InputStream中,可以通过 int read() 方法来从流中读取一个字节,批量读取字节可以通过 int read(byte[] b) 或者 int read(byte[] b, int off, int len) 来实现,这两个方法的返回值为实际读取到的字节数。如果需要重复读取流中某段数据,可以在读取之前先使用 void mark(int readlimit) 方法在当前位置做一个记号,之后通过 void reset() 方法返回到之前做标记的位置,不过在做这些标记操作之前,需要先通过 boolean markSupported() 方法来确定该流是否支持标记。如果对某些可预知的数据不感兴趣,可以使用 long skip(long n) 来调过一些流中的一些数据。

使用完流,无论是输入还是输出流,都要调用其 close() 方法对其进行关闭。

装饰器模式

装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。

这种设计模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。

以InputStream为例,它是一个抽象类:

public abstract class InputStream implements Closeable {
    ...
    ...
}

并定义有抽象方法

public abstract int read() throws IOException;

该抽象方法由具体的子类去实现,通过InputStream的族谱图可以看到,直接继承了InputStream,并且提供某一特定功能的子类有:

  • ByteArrayInputStream
  • FileInputStream
  • ObjectInputStream
  • PipedInputStream
  • SequenceInputStream
  • StringBufferInputStream

这些子类都具有特定的功能,比如说,FileInputStream代表一个文件输入流并提供读取文件内容的功能,ObjectInputStream提供了对象反序列化的功能。

InputStream这个抽象类有一个子类与上述其它子类非常不同,这个子类就是 FilterInputStream ,可参见上图中的InputStream族谱图。

翻开FilterInputStream的代码,我们可以看到,它内部又维护了一个InputStream的成员对象,并且它的所有方法,都是调用这个成员对象的同名方法。换句话说,FilterInputStream它什么事都不做。就是把调用委托给内部的InputStream成员对象。如下所示:

public class FilterInputStream extends InputStream {
    protected volatile InputStream in;

    protected FilterInputStream(InputStream in) {
        this.in = in;
    }

    public int read() throws IOException {
        return in.read();
    }

    public int read(byte b[]) throws IOException {
        return read(b, 0, b.length);
    }

    public int read(byte b[], int off, int len) throws IOException {
        return in.read(b, off, len);
    }

    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();
    }

FilterInputStream的又有其子类,分别是:

  • BufferedInputStream
  • DataInputStream
  • LineNumberInputStream
  • PushbackInputStream

虽然从上面代码看FilterInputStream并没有做什么有卵用的事,但是它的子类可不同了,以BufferedInputStream为例,这个类提供了提前读取数据的功能,也就是缓冲的功能。可以看看它的read方法:

    public synchronized int read() throws IOException {
        if (pos >= count) {
            fill();
            if (pos >= count)
                return -1;
        }
        return getBufIfOpen()[pos++] & 0xff;
    }

可以看到,当pos>=count时,意即需要提前缓冲一些数据的时候到了,那么就会调用fill()将缓冲区加满,以便后续读取。 由于本文只讨论io流的装饰器模式,所以关于具体实现细节将不会展开讨论,比如本文不会讨论fill()方法是如何实现的,在这里可以先将它当做一个黑盒子。

从这里可以开始感受到,BufferedInputStream就是一个装饰者,它能为一个原本没有缓冲功能的InputStream添加上缓冲的功能。

比如我们常用的FileInputStream,它并没有缓冲功能,我们每次调用read,都会向操作系统发起调用索要数据。假如我们通过BufferedInputStream来 装饰 它,那么每次调用read,会预先向操作系统多拿一些数据,这样就不知不觉中提高了程序的性能。如以下代码所示:

BufferedInputStream bis = new BufferedInputStream(new FileInputStream(new File("/home/user/abc.txt")));

同理,对于其它的FilterInputStream的子类,其作用也是一样的,那就是装饰一个InputStream,为它添加它原本不具有的功能。OutputStream以及家属对于装饰器模式的体现,也以此类推。

JDK中的io流的设计是设计模式中装饰器模式的一个经典示范,如果细心发现,JDK中还有许多其它设计模式的体现,比如说监听者模式等等。

时间: 2024-10-02 05:03:38

Java IO流以及装饰器模式在其上的运用的相关文章

《java与设计模式》之装饰模式详解&Java IO中的装饰器模式

1 概述 在一个项目中,你会有非常多的因素考虑不到,特别是业务的变更,不时的冒出一个需求是很正常的情况.有三个继承关系的类:Father.Son.GrandSon,我们要在Son类上增强一些功能怎么办?给Son类增加方法吗?那对GrandSon的影响呢?特别是对GrandSon有多个的情况,你会怎么办?认真看完本文,你会找到你的答案. JavaIO中,像下面的嵌套语句是不是很常见,为什么要怎样定义呢?理解装饰模式后,你会找到答案. DataInputStream in = new DataInp

设计模式学习之装饰模式:IO流的装饰器

IO流的装饰器 题目分析:通过对java的io系列类分析得知,java的io流使用了设计模式中的装饰模式,以动态的给一个对象增加职责,能够更加灵活的增加功能.通过看io的源代码得知FilterOutputStream类继承了OutputStream类并拥有父类的一个对象,它和父类具有组合聚合的关系.因此要实现我们自己的加密类只需扩展FilterOutputStream类重写它的wite方法即可 UML图: 源代码: package com.cmc import java.io.FilterOut

IO中的装饰器模式

//可以进InputStream 类 区分为目的和方法两类 //一般直接子类,都是目的不同的(A类), // 如FileInputStream, #从文件中获得字节.// ByteArrayInputStream #包含一个内存缓冲区,字节从中取出.// ObjectInputStream #用来恢复被序列化的对象.// PipedInputStream #管道输入流,读取管道内容.多和PipedOutputStream一起用于多线程通信.// SequenceInputStream #是多种输

IO流与装饰者模式

java使用IO流来处理不同设备之间数据的交互;所有的IO操作实际上都是对 Stream 的操作 从功能上划分: 输入流: 当数据从源进入的编写的程序时,称它为输入流; 输出流: 从程序输出回另一个源成为输出流; 输入与输出是有参照物的,而这个参照物就是应用程序本身 从结构上划分: 总体的大纲分为两部分,字节流和字符流的封装类体系 首先说: 什么是字节流? 按照字节读取的流对象,一次读取一个字节 1字节 占八位 一个数字占四个字节, (前三个八位补0) 什么是字符流? 按照字符读取的流对象,一次

IO流之装饰者模式

工人 /                      \ 水管工                   木匠 /            \                 /           \ A公司水管工  B公司水管工  A公司木匠    B公司木匠 如上图所示,如果我们要实现AB公司的水管工和木匠,则要实现四个类.分别继承水管工和木匠的基类,如果需要在加个C公司呢,就显得特别繁琐,使用 装饰者模式可以很好的解决这一问题,各个文件的代码如下 1.Worker.java文件 interfac

设计模式——装饰器模式

装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构.这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装. 装饰器模式结构图 Component(抽象构件):它是装饰类和具体构件的公共父类(一般是接口或者抽象类): ConcreteComponent(具体构件):具它是抽象构件对象的子类,用来定义具体的构件对象(Component的子类或者具体实现): Decorator(抽象装饰类):进继承抽象构件,用于给具体的构件添加一些新的职责(一

Java设计模式(四) 装饰器模式 代理器模式

(七)装饰器模式 Decorator 装饰器模式是为了动态的给一个对象增加一些新功能.装饰对象与被装饰的对象需要实现同一个接口,装饰对象持有被装饰对象的实例. interface DecoratorSourceable{ public void method(); } //被装饰类 class DecoratorSource implements DecoratorSourceable{ public void method(){ System.out.println("Source"

Java IO流学习总结

Java流操作有关的类或接口: Java流类图结构: 流的概念和作用 流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象.即数据在两设备间的传输称为流,流的本质是数据传输,根据数据传输特性将流抽象为各种类,方便更直观的进行数据操作. IO流的分类 根据处理数据类型的不同分为:字符流和字节流 根据数据流向不同分为:输入流和输出流 字符流和字节流 字符流的由来: 因为数据编码的不同,而有了对字符进行高效操作的流对象.本质其实就是基于字节流读取时,去查了指定的码表. 字节流和字符流的区

Java IO流学习总结(转)

原文地址:http://www.cnblogs.com/oubo/archive/2012/01/06/2394638.html Java流操作有关的类或接口: Java流类图结构: 流的概念和作用 流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象.即数据在两设备间的传输称为流,流的本质是数据传输,根据数据传输特性将流抽象为各种类,方便更直观的进行数据操作.   IO流的分类 根据处理数据类型的不同分为:字符流和字节流 根据数据流向不同分为:输入流和输出流 字符流和字节流 字符