java io 装饰流_java IO流的继承体系和装饰类应用

java IO流的设计是基于装饰者模式&适配模式,面对IO流庞大的包装类体系,核心是要抓住其功能所对应的装饰类。

装饰模式又名包装(Wrapper)模式。装饰模式以对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案。装饰模式通过创建一个包装对象,也就是装饰,来包裹真实的对象。装饰模式以对客户端透明的方式动态地给一个对象附加上更多的责任。换言之,客户端并不会觉得对象在装饰前和装饰后有什么不同。装饰模式可以在不创造更多子类的情况下,将对象的功能加以扩展。装饰模式把客户端的调用委派到被装饰类。装饰模式的关键在于这种扩展是完全透明的。

cca6b436143f0b81a23d40b1d2bd5073.png

装饰者的角色:

抽象构件角色(Component):给出一个抽象接口,以规范准备接收附加责任的对象。

具体构件角色(Concrete Component):定义将要接收附加责任的类。

装饰角色(Decorator):持有一个构件(Component)对象的引用,并定义一个与抽象构件接口一致的接口。

具体装饰角色(Concrete Decorator):负责给构件对象“贴上”附加的责任。

实现案例:

//抽象构件角色

public interfaceComponent

{public voiddoSomething();

}

//具体构件角色

public class ConcreteComponent implementsComponent

{

@Overridepublic voiddoSomething()

{

System.out.println("功能A");

}

}

//装饰者角色

public class Decorator implementsComponent

{//维护一个抽象构件角色

privateComponent component;publicDecorator(Component component)

{this.component =component;

}

@Overridepublic voiddoSomething()

{

component.doSomething();

}

}

//具体装饰者角色

public class ConcreteDecorator1 extendsDecorator

{publicConcreteDecorator1(Component component)

{super(component);

}

@Overridepublic voiddoSomething()

{super.doSomething();this.doAnotherThing();

}private voiddoAnotherThing()

{

System.out.println("功能B");

}

}

以上就是装饰者模式的一个极简代码思路,实际上IO流的装饰体系也是在对上面思路的一中具体实现。

JAVA-IO流体系:

在IO中,具体构件角色是节点流,装饰角色是过滤流。

1、继承自InputStream/OutputStream的流都是用于向程序中输入/输出数据,且数据的单位都是字节(byte=8bit),如图,深色的为节点流,浅色的为过滤流。

7db486dbf63b2bffdc9f7ead96465105.png

2、继承自Reader/Writer的流都是用于向程序中输入/输出数据,且数据的单位都是字符(2byte=16bit),如图,深色的为节点流,浅色的为过滤流。

f1502deb57468ea3bff06d95e2fa2961.png

从图中可以看出,InputStream就是装饰者模式中的超类(Component),ByteArrayInputStream,FileInputStream相当于被装饰者(ConcreteComponent),这些类都提供了最基本的字节读取功能。而另外一个和这两个类是同一级的类FilterInputStream即是装饰者(Decorator),BufferedInputStream,DataInputStream,PushbackInputStream…这些都是被装饰者装饰后形成的成品。为什么可以说:装饰模式可以在不创造更多子类的情况下,将对象的功能加以扩展,能理解这一点就能很好的掌握装饰者设计模式的精髓,如果在InputStream这里扩展出FilterInputStream类下面的装饰类,那么针对FileInputStream和ByteArrayInputStream就都要去实现一次BufferedInputStream了,那么可能就会衍生出BufferedFileInputStream和BufferedByteArrayInputStream这样的类,如果按照这样的扩展方式去添加功能,对于添加功能的子类来说简直是一场噩梦,好在装饰着模式很好的解决了这个问题,现在我们只需要在过滤流类这里维护一个超类,不论传入的是什么具体的节点流,那么都只要套一层装饰,就能对功能方法进行加强。

如果想要对文件输入流进行缓存加强可以这样装饰:

File file = new File ("hello.txt");BufferedInputStream inBuffered=new BufferedInputStream (new FileInputStream(file));

如果想要对字节数组输入流进行缓存加强可以这样装饰:

byte[] byts="Hello".getBytes();

BufferedInputStream bf=new BufferedInputStream(new ByteArrayInputStream(byts));

那么节点流上的类就可以平行扩展,而装饰者同样可以按照功能进行另外一个维度的扩展,调用的时候就可以按需进行组合装饰,这样就可以减少了子类还将对象的功能进行扩展,不得不佩服前人在该设计模式上的智慧,理解了这装饰着模式后,就应该对java中IO流的体系进行梳理:

节点流类型

对文件操作的字符流有FileReader/FileWriter,

字节流有FileInputStream/FileOutputStream。

过滤流类型

缓冲流:缓冲流要“套接”在相应的节点流之上,对读写的数据提供了缓冲的功能,提高了读写效率,同时增加了一些新的方法。字节缓冲流有BufferedInputStream /BufferedOutputStream,字符缓冲流有BufferedReader / BufferedWriter,字符缓冲流分别提供了读取和写入一行的方法ReadLine和NewLine方法。

对于输出的缓冲流,写出的数据,会先写入到内存中,再使用flush方法将内存中的数据刷到硬盘。所以,在使用字符缓冲流的时候,一定要先flush,然后再close,避免数据丢失。

转换流:用于字节数据到字符数据之间的转换。

字符流InputStreamReader / OutputStreamWriter。其中,InputStreamReader需要与InputStream“套接”,OutputStreamWriter需要与OutputStream“套接”。

数据流:提供了读写Java中的基本数据类型的功能。

DataInputStream和DataOutputStream分别继承自InputStream和OutputStream,需要“套接”在InputStream和OutputStream类型的节点流之上。

对象流:用于直接将对象写入写出。

流类有ObjectInputStream和ObjectOutputStream,本身这两个方法没什么,但是其要写出的对象有要求,该对象必须实现Serializable接口,来声明其是可以序列化的。否则,不能用对象流读写。(api以及demo在文末)

重点梳理一下:Java中Inputstream/OutputStream与Reader/Writer的区别

IO流的应用选择

1、确定选用流对象的步骤

确定原始数据的格式

确定是输入还是输出

是否需要转换流

数据的来源(去向)

是否需要缓冲

是否需要格式化输出

按照数据格式分

二进制格式(只要确定不是纯文本格式的),InputStream, OutputStream, 及其所有带Stream子类

纯文本格式(比如英文/汉字/或其他编码文字):Reader, Writer, 及其相关子类

按照输入输出分

输入:Reader, InputStream,及其相关子类

输出:Writer,OutputStream,及其相关子类

按缓冲功能分

要缓冲:BufferedInputStream, BufferedOuputStream, BuffereaReader, BufferedWriter

按照格式化输出

需要格式化输出:PrintStream(输出字节),PrintWriter(输出字符)

特殊需求

从Stream转化为Reader,Writer:InputStreamReader,OutputStreamWriter

对象输入输出流:ObjectInputStream,ObjectOutputStream

进程间通信:PipeInputStream,PipeOutputStream,PipeReader,PipeWriter

合并输入:SequenceInputStream

更特殊的需要:PushbackInputStream, PushbackReader, LineNumberInputStream, LineNumberReader

//对象流案例

public classDemo3 {public static void main(String[] args) throwsIOException,

ClassNotFoundException {

Cat cat= new Cat("tom", 3);

FileOutputStream fos= new FileOutputStream(new File("c:\\Cat.txt"));

ObjectOutputStream oos= newObjectOutputStream(fos);

oos.writeObject(cat);

System.out.println(cat);

oos.close();//反序列化

FileInputStream fis = new FileInputStream(new File("c:\\Cat.txt"));

ObjectInputStream ois= newObjectInputStream(fis);

Object readObject=ois.readObject();

Cat cat2=(Cat) readObject;

System.out.println(cat2);

fis.close();

}class Cat implementsSerializable {publicString name;public intage;publicCat() {

}public Cat(String name, intage) {this.name =name;this.age =age;

}

@OverridepublicString toString() {return "Cat [name=" + name + ", age=" + age + "]";

}

}

//DataInputStream 基本数据类型和String//操作基本数据类型的方法:

int readInt()://一次读取四个字节,并将其转成int值。

boolean readBoolean()://一次读取一个字节。

shortreadShort();longreadLong();//剩下的数据类型一样。

String readUTF()://按照utf-8修改版读取字符。注意,它只能读writeUTF()//写入的字符数据。

DataOutputStream

DataOutputStream(OutputStream)://操作基本数据类型的方法:

writeInt(int)://一次写入四个字节。//注意和write(int)不同。write(int)只将该整数的最低一个8位写入。剩余三个8位丢弃。

writeBoolean(boolean);

writeShort(short);

writeLong(long);//剩下是数据类型也也一样。

writeUTF(String)://按照utf-8修改版将字符数据进行存储。只能通过readUTF读取。

转换流:

InputStreamReader:字节到字符的桥梁。

OutputStreamWriter:字符到字节的桥梁。

//从字节流中读取字符信息

BufferedReader bf=new InputStreamReader(new FileInputStream("src"));//将字符信息用指定字节编码写出

OutputStreamWriter bw=new OutputStreamWriter(new FileOutputStream("target"),"utf-8");

bw.write("Hello");

public classTestIo {public classDemo4 {public static void main(String[] args) throwsIOException {

File file= new File("c:\\a.txt");

File fileGBK= new File("c:\\gbk.txt");

File fileUTF= new File("c:\\utf.txt");//写入//使用系统默认码表写入

testWriteFile(file);//使用gbk编码向gbk文件写入信息

testWriteFile(fileGBK, "gbk");//使用utf-8向utf-8文件中写入信息

testWriteFile(fileUTF, "utf-8");//读取//默认编码

testReadFile(file);//传入gbk编码文件,使用gbk解码

testReadFile(fileGBK, "gbk");//传入utf-8文件,使用utf-8解码

testReadFile(fileUTF, "utf-8");

}//使用系统码表将信息写入到文件中

private static void testWriteFile(File file) throwsIOException {

FileOutputStream fos= newFileOutputStream(file);

OutputStreamWriter ops= newOutputStreamWriter(fos);

ops.write("中国");

ops.close();

}//使用指定码表,将信息写入到文件中

private static voidtestWriteFile(File file, String encod)throwsIOException {

FileOutputStream fos= newFileOutputStream(file);

OutputStreamWriter ops= newOutputStreamWriter(fos, encod);

ops.write("中国");

ops.close();

}//该方法中nputStreamReader使用系统默认编码读取文件.

private static void testReadFile(File file) throwsIOException {

FileInputStream fis= newFileInputStream(file);

InputStreamReader ins= newInputStreamReader(fis);int len = 0;while ((len = ins.read()) != -1) {

System.out.print((char) len);

}

ins.close();

}//该方法适合用指定编码读取文件

private static voidtestReadFile(File file, String encod)throwsIOException {

FileInputStream fis= newFileInputStream(file);

InputStreamReader ins= newInputStreamReader(fis, encod);int len = 0;while ((len = ins.read()) != -1) {

System.out.print((char) len);

}

ins.close();

}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值