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ストリームのデコレーション
        机能を简単にして、英语を暗号化して保存することを実现しましょう.暗号化アルゴリズムとは言えません.英语のアルファベットを后に2つの位置に移动します.例えば、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ストリームはキャッシュ付きストリームであるため、デフォルトのキャッシュ8192 byte、つまりデフォルトのストリームのキャッシュデータが8192 byteに達した場合、キャッシュ内のデータが自動的に出力されます.
•現在出力されるバイトは8192 byte未満であるため、自動的に出力されずに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ストリームはキャッシュ付きストリームであるため、デフォルトのキャッシュ8192 byte、つまりデフォルトのストリームのキャッシュデータが8192 byteに達した場合、キャッシュ内のデータが自動的に出力されます.
•現在出力されるバイトは8192 byte未満であるため、自動的に出力されずにBufferedOutputStreamストリームにデータがキャッシュされます.
•「dout.close();」という文を実行すると、DataOutputStreamを閉じるように呼び出されます.これは、DataOutputStreamストリームに流れるcloseメソッド、つまりEncryptOutputStreamのcloseメソッドに移行します.一方、EncryptOutputStreamのcloseメソッドはOutputStreamから継承され、OutputStreamのcloseメソッド実装では空のメソッドで、何もしていません.したがって,この実現方式はflushストリームのデータがなく,ファイルの内容も出力されず,当然空白である.