I/O操作中用到装饰模式(转自chjavach)

1,java io中装饰器的利用例子
package decorationApp;

import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.FileInputStream;
//装饰器的典型应用
public class IOTest {
	public static void main(String[] args)throws Exception  {
		//流式读取文件
		DataInputStream din = null;
		try{
			din = new DataInputStream(
				new BufferedInputStream(
						new FileInputStream("IOTest.txt")  //文件放在项目目录下,不是src下,也不是同包下
				)
			);
			//然后就可以获取文件内容了
			byte bs []= new byte[din.available()]; 
			din.read(bs);
			String content = new String(bs);
			System.out.println("文件内容===="+content);
		}finally{
			if(din!=null)din.close();
		}		
	}
}

仔细观察上面的代码,会发现最里层是一个FileInputStream对象,然后把它传递给一个BufferedInputStream对象,经过BufferedInputStream处理过后,再把处理过后的对象传递给了DataInputStream对象进行处理,这个过程其实就是装饰器的组装过程,FileInputStream对象相当于原始的被装饰的对象,而BufferedInputStream对象和DataInputStream对象则相当于装饰器。

2,自己实现的I/O流的装饰器
        来个功能简单点的,实现把英文加密存放吧,也谈不上什么加密算法,就是把英文字母向后移动两个位置,比如:a变成c,b变成d,以此类推,最后的y变成a,z就变成b,而且为了简单,只处理小写的,够简单的吧。

package decorationApp;

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

/**
 * 实现简单的加密,对OutputStream进行装饰
 */
public class EncryptOutputStream  extends OutputStream{
	//持有被装饰的对象
	private OutputStream os = null;
	
	public EncryptOutputStream(OutputStream os){
		this.os = os;
	}	
	public void write(int a) throws IOException {
		//先统一向后移动两位
		a = a+2;
		//97是小写的a的码值
		if(a >= (97+26)){
			//如果大于,表示已经是y或者z了,减去26就回到a或者b了
			a = a-26;
		}
		this.os.write(a);
	}
}

测试程序:
package decorationApp;

import java.io.BufferedOutputStream;
import java.io.DataOutputStream;
import java.io.FileOutputStream;

public class Client {
	public static void main(String[] args) throws Exception {
		//流式输出文件
		DataOutputStream dout = new DataOutputStream(
			new BufferedOutputStream(
				//这是我们加的装饰器
				new EncryptOutputStream(
					new FileOutputStream("MyEncrypt.txt")))); //如果没有项目目录下没有此文件,会自动创建该文件
		//然后就可以输出内容了
		dout.write("abcdxyz".getBytes()); //如果文件中有内容将被重新写入
		dout.close();
	}
}

生成的MyEncrypt.txt文件中内容:cdefzab

如果上面的程序,装饰器的顺序改变如下:
//流式输出文件
DataOutputStream dout = new DataOutputStream(
			//换了个位置
			new EncryptOutputStream (
				new BufferedOutputStream(
					new FileOutputStream("MyEncrypt.txt"))));


这个时候输出的文件一片空白,什么都没有。这是哪里出了问题呢?
(1)先看看成功输出流中的内容的写法的运行过程:




•当执行到“dout.write("abcdxyz".getBytes());”这句话的时候,会调用DataOutputStream的write方法,把数据输出到BufferedOutputStream中;
•由于BufferedOutputStream流是一个带缓存的流,它默认缓存8192byte,也就是默认流中的缓存数据到了8192byte,它才会自动输出缓存中的数据;
•而目前要输出的字节肯定不到8192byte,因此数据就被缓存在BufferedOutputStream流中了,而不会被自动输出
•当执行到“dout.close();”这句话的时候:会调用关闭DataOutputStream流,这会转调到传入DataOutputStream中的流的close方法,也就是BufferedOutputStream的close方法,而BufferedOutputStream的close方法继承自FilterOutputStream,在FilterOutputStream的close方法实现里面,会先调用输出流的方法flush,然后关闭流。也就是此时BufferedOutputStream流中缓存的数据会被强制输出;
•BufferedOutputStream流中缓存的数据被强制输出到EncryptOutputStream流,也就是我们自己实现的流,没有缓存,经过处理后继续输出;
•EncryptOutputStream流会把数据输出到FileOutputStream中,FileOutputStream会直接把数据输出到文件中,因此,这种实现方式会输出文件的内容。




(2)再来看看不能输出流中的内容的写法的运行过程:

•当执行到“dout.write("abcdxyz".getBytes());”这句话的时候,会调用DataOutputStream的write方法,把数据输出到EncryptOutputStream中;
•EncryptOutputStream流,也就是我们自己实现的流,没有缓存,经过处理后继续输出,把数据输出到BufferedOutputStream中;
•由于BufferedOutputStream流是一个带缓存的流,它默认缓存8192byte,也就是默认流中的缓存数据到了8192byte,它才会自动输出缓存中的数据;
•而目前要输出的字节肯定不到8192byte,因此数据就被缓存在BufferedOutputStream流中了,而不会被自动输出
•当执行到“dout.close();”这句话的时候:会调用关闭DataOutputStream流,这会转调到传入DataOutputStream流中的流的close方法,也就是EncryptOutputStream的close方法,而EncryptOutputStream的close方法继承自OutputStream,在OutputStream的close方法实现里面,是个空方法,什么都没有做。因此,这种实现方式没有flush流的数据,也就不会输出文件的内容,自然是一片空白了。

你可能感兴趣的:(java,算法,OS)