天天看点

第21天 输入字符流、输出字符流、缓冲字符流、装饰者模式

1.输入字符流

1.1输入输出字节流回顾

字节流: 

输入字节流

----------| InputStream 输入字节流的基类   抽象类

-------------|FileInputStream 读取文件数据的输入字节流。

-------------|BufferedInputStream 缓冲输入字节流

缓冲输入字节流出现的目的: 为了提高读取文件数据的效率。 该类其实内部就是维护了一个8kb字节数组而已。

输出字节流:

---------| OutputStream 输出字节流的基类。  抽象类。

--------------| FileOutStream  向文件输出数据的输出字节流。

--------------| BufferedOutputStream 缓冲输出字节流。  该类出现的目的是为了提高写数据的效率 。 其实该类内部也是维护了一个8kb的数组而已,当调用其write方法的时候数据默认是向它内部的数组中存储 的,只有调用flush方法或者是close方法或者是8kb的字节数组存储满数据的时候才会真正的向硬盘输出。

使用字节流读取和写入中文

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Arrays;
public class Demo1 {
	public static void main(String[] args) throws IOException {
//		writeTest();
		readrTest();
	}
	//使用字节流读取中文
	public static void readrTest() throws IOException{
		//找到目标文件
		File file = new File("F:\\a.txt");
		//建立数据的输入通道
		FileInputStream fileInputStream = new FileInputStream(file);
		//读取内容
		//int content = 0;
		/*while((content = fileInputStream.read())!=-1){ //出现乱码的原因: 一个中文在gbk码表中默认是占两个字节,
	   // 目前你只读取了一个字节而已,所以不是一个完整的中文。
			System.out.print((char)content);
		}*/
		byte[] buf = new byte[2];
		for(int i = 0 ; i < 3 ; i++){
			fileInputStream.read(buf);
			System.out.print(new String(buf));
		}
		//关闭资源
		fileInputStream.close();
		
	}
	//使用字节流写中文。   字节流之所以能够写中文是因为借助了字符串的getBytes方法对字 
符串进行了编码(字符---->数字)。 
	public static void writeTest() throws IOException{
		//找到目标文件
		File file = new File("F:\\a.txt");
		//建立数据的输出通道
		FileOutputStream fileOutputStream  = new FileOutputStream(file);
		//准备数据,把数据写出。
		String data = "大家好";
		byte[] buf = data.getBytes();	//把字符串转换成字节数组
		System.out.println("输出的内容:"+ Arrays.toString(buf));
		fileOutputStream.write(buf);
		///关闭资源
		fileOutputStream.close();
	}
}
           

1.2字符流

计算机并不区分二进制文件与文本文件。所有的文件都是以二进制形式来存储的,因此,从本质上说,所有的文件都是二进制文件。所以字符流是建立在字节流之上的,它能够提供字符层次的编码和解码。例如,在写入一个字符时,Java虚拟机会将字符转为文件指定的编码(默认是系统默认编码),在读取字符时,再将文件指定的编码转化为字符。

1.3常见的码表如下:

ASCII:    美国标准信息交换码。用一个字节的7位可以表示。

ISO8859-1: 拉丁码表。欧洲码表,用一个字节的8位表示。又称Latin-1(拉丁编码)或“西欧语言”。ASCII码是包含的仅仅是英文字母,并且没有完全占满256个编码位置,所以它以ASCII为基础,在空置的0xA0-0xFF的范围内,加入192个字母及符号,

藉以供使用变音符号的拉丁字母语言使用。从而支持德文,法文等。因而它依然是一个单字节编码,只是比ASCII更全面。

GB2312: 英文占一个字节,中文占两个字节.中国的中文编码表。

GBK:   中国的中文编码表升级,融合了更多的中文文字符号。

Unicode:  国际标准码规范,融合了多种文字。所有文字都用两个字节来表示,Java语言使用的就是unicode。

UTF-8:    最多用三个字节来表示一个字符。

(我们以后接触最多的是iso8859-1、gbk、utf-8)

查看上述码表后,很显然中文的‘中’在iso8859-1中是没有对映的编码的。或者一个字符在2中码表中对应的编码不同,例如有一些字在不同的编码中是有交集的,例如bjg5 和gbk 中的汉字简体和繁体可能是一样的,就是有交集,但是在各自码表中的数字不一样。

例如

使用gbk 将中文保存在计算机中,

   中  国

对映 100  200   如果使用big5 打开

可能   ?  ...  

不同的编码对映的是不一样的。

很显然,我们使用什么样的编码写数据,就需要使用什么样的编码来对数据。

ISO8859-1:一个字节

GBK: 两个字节包含了英文字符和扩展的中文 ISO8859-1+中文字符

UTF-8万国码,推行的。是1~3个字节不等长。英文存的是1个字节,中文存的是3个字节,是为了节省空间。

字节流:字节流读取的是文件中的二进制数据,读到的数据并不会帮你转换成你看得懂的字符。

字符流: 字符流会把读取到的二进制的数据进行对应 的编码与解码工作。   字符流= 字节流 + 编码(解码)

输入字符流:

----------| Reader 输入字符流的基类   抽象类

-------------| FileReader 读取文件的输入字符流。

FileReader的用法:

   1. 找到目标文件

   2. 建立数据的输入通道

   3. 读取数据

   4. 关闭资源

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
public class Demo2 {
	public static void main(String[] args) throws IOException {
		readTest2();
	}
	
	//使用缓冲字符数组读取文件。
	public static void readTest2() throws IOException{
		//找到目标文件
		File file = new File("F:\\1208project\\day21\\src\\day21\\Demo1.java");
		// 建立数据的输入通道
		FileReader fileReader = new FileReader(file);
		//建立缓冲字符数组读取文件数据
		char[] buf = new char[1024];
		int length = 0 ; 
		while((length = fileReader.read(buf))!=-1){
			System.out.print(new String(buf,0,length));
		}
	}
	public static void readTest1() throws IOException{
		//找到目标文件
		File file = new File("F:\\1208project\\day21\\src\\day21\\Demo1.java");
		//建立数据的输入通道
		FileReader fileReader = new FileReader(file);
		int content = 0 ;
		while((content = fileReader.read())!=-1){ //每次只会读取一个字符,效率低。
			System.out.print((char)content);
		}
		//关闭资源
		fileReader.close();
	}
}
           

1.4 Reader

方法:

intread():

读取一个字符。返回的是读到的那个字符。如果读到流的末尾,返回-1.

intread(char[]):

将读到的字符存入指定的数组中,返回的是读到的字符个数,也就是往数组里装的元素的个数。如果读到流的末尾,返回-1.

close()

读取字符其实用的是window系统的功能,就希望使用完毕后,进行资源的释放

由于Reader也是抽象类,所以想要使用字符输入流需要使用Reader的实现类。查看API文档。找到了FileReader。

1,用于读取文本文件的流对象。

2,用于关联文本文件。

构造函数:在读取流对象初始化的时候,必须要指定一个被读取的文件。

如果该文件不存在会发生FileNotFoundException.

public class IoTest1_Reader {
	public static void main(String[] args) throws Exception {
		String path = "c:/a.txt";
		// readFileByInputStream(path);
		readFileByReader(path);
	}

	/**
	 * 使用字节流读取文件内容
	 * @param path
	 */
	public static void readFileByInputStream(String path) throws Exception {
		InputStream in = new FileInputStream(path);

		int len = 0;
		while ((len = in.read()) != -1) {
			System.out.print((char) len);
		}

		in.close();
	}

	/**
	 * 使用字符流读取文件内容
	 */
	public static void readFileByReader(String path) throws Exception {
		Reader reader = new FileReader(path);
		int len = 0;
		while ((len = reader.read()) != -1) {
			System.out.print((char) len);
		}

		reader.close();
	}

}
           

2.输出字符流

2.1 Writer

Writer中的常见的方法:

1) write(ch): 将一个字符写入到流中。

2) write(char[]): 将一个字符数组写入到流中。

3) write(String): 将一个字符串写入到流中。

4) flush():刷新流,将流中的数据刷新到目的地中,流还存在。

5) close():关闭资源:在关闭前会先调用flush(),刷新流中的数据去目的地。然流关闭。

发现基本方法和OutputStream 类似,有write方法,功能更多一些。可以接收字符串。

同样道理Writer是抽象类无法创建对象。查阅API文档,找到了Writer的子类FileWriter

1:将文本数据存储到一个文件中。

public class IoTest2_Writer {
	public static void main(String[] args) throws Exception {
		String path = "c:/ab.txt";

		writeToFile(path);
	}
	/**
	 * 写指定数据到指定文件中
	 * 
	 */
	public static void writeToFile(String path) throws Exception {
		Writer writer = new FileWriter(path);
		writer.write('中');
		writer.write("世界".toCharArray());
		writer.write("中国");

		writer.close();
	}
}
2:追加文件:
默认的FileWriter方法新值会覆盖旧值,想要实现追加功能需要
使用如下构造函数创建输出流 append值为true即可。
FileWriter(String fileName, boolean append)
FileWriter(File file, boolean append)
3:flush方法
	如果使用字符输出流,没有调用close方法,会发生什么?
private static void writeFileByWriter(File file) throws IOException {
		FileWriter fw = new FileWriter(file);
		fw.write('新');
fw.flush();
		fw.write("中国".toCharArray());
		fw.write("世界你好!!!".toCharArray());
		fw.write("明天");	
		// 关闭流资源
		//fw.close();
	}
程序执行完毕打开文件,发现没有内容写入.原来需要使用flush方法. 刷新该流的缓冲。
为什么只要指定claose方法就不用再flush方法,因为close也调用了flush方法.
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
输出字符流:
------| Writer 输出字符流的基类。 抽象类
-----------| FileWriter 向文件数据数据的输出字符流
FileWriter的使用步骤:
	1. 找到目标文件。
	2. 建立数据输出通道
	3. 写出数据。
	4. 关闭资源
FileWriter要注意的事项:
	1. 使用FileWriter写数据的时候,FileWriter内部是维护了一个1024个字符数组的,写数据的时候会先写入到它内部维护的字符数组中,如果需要
	把数据真正写到硬盘上,需要调用flush或者是close方法或者是填满了内部的字符数组。
	2. 使用FileWriter的时候,如果目标文件不存在,那么会自动创建目标文件。
	3.使用FileWriter的时候, 如果目标文件已经存在了,那么默认情况会先情况文件中的数据,然后再写入数据 , 如果需要在原来的基础上追加数据,
	需要使用“new FileWriter(File , boolean)”的构造方法,第二参数为true。
public class Demo1 {
	public static void main(String[] args) throws IOException {
		writeTest1();
	}
	
	public static void  writeTest1() throws IOException{
		//找到目标文件
		File file = new File("F:\\a.txt");
		//建立数据输出通道
		FileWriter fileWriter = new FileWriter(file,true);
		//准备数据,把数据写出
		String data = "今天天气非常好!!";
		fileWriter.write(data);  //字符流具备解码的功能。
		//刷新字符流
//		fileWriter.flush();
		//关闭资源
		fileWriter.close();	
	}
}
           

3.字符流与字节流拷贝文件

练习: 使用字符流拷贝一个文本文件(java文件).

接着使用字符流拷贝一个图片(观察图片的大小变化,思考为什么会这样子??)

何时使用字符流,何时使用字节流?依据是什么?

使用字符流的应用场景: 如果是读写字符数据的时候则使用字符流。

使用字节流的应用场景: 如果读写的数据都不需要转换成字符的时候,则使用字节流。

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
//使用字符流拷贝文件
public class Copy {
	public static void main(String[] args) throws IOException {
		BufferedReader bufferedReader = new BufferedReader(new FileReader("F:\\Test.txt"));
		BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("E:\\Test.exe"));
		String line=null;
		while((line = bufferedReader.readLine())!=null){
		bufferedWriter.write(line);
		}
		bufferedWriter.close();
		bufferedReader.close();
	}
}
使用字节流读取中文
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;

//使用字节流读取中文
public class Demo2 {

	public static void main(String[] args) throws IOException {
		File file = new File("F:\\a.txt");
		FileInputStream fileInputStream = new FileInputStream(file);
		byte[] buf = new byte[1024];
		int length = 0;
		while((length = fileInputStream.read(buf))!=-1){
			System.out.println(new String(buf,0,length)); //借用字符串的解码功能。
		}
	}
}
           

4.缓冲输入字符流

输入字符流:

-------| Reader 所有输入字符流的基类。 抽象类

----------| FileReader 读取文件字符串的输入字符流。

----------|BufferedReader   缓冲输入字符流  。 缓冲 输入字符流出现的目的是为了提高读取文件 的效率和拓展了FileReader的功能。  其实该类内部也是维护了一个字符数组

记住:缓冲流都不具备读写文件的能力。

BufferedReader的使用步骤:

   1.找到目标文件

   2 .建立数据的输入通道。

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.Arrays;
public class Demo1 {
	public static void main(String[] args) throws IOException {
//		 readTest1();
		File file  = new File("F:\\ buffered\\Demo1.java");
		//建立数据的输入通道。
		FileReader fileReader = new FileReader(file);
		String line =  null;
		while((line = myReadLine(fileReader))!=null){
			System.out.println(line);
		}
	}
	//自己去实现readLine方法。
	public static String myReadLine(FileReader fileReader) throws IOException{
		//创建一个字符串缓冲类对象
		StringBuilder sb = new StringBuilder();  //StringBuilder主要是用于存储读取到的数据
		int content = 0 ;
		while((content = fileReader.read())!=-1){
			if(content=='\r'){
				continue;
			}else if(content=='\n'){
				break;
			}else{
				//普通字符
				sb.append((char)content);
			}
		}
		//代表已经读取完毕了。
		if(content ==-1){
			return null;
		}
		
		return sb.toString();  
	}
	public static void readTest1() throws IOException{
		//找到目标文件
		File file  = new File("F:\\a.txt");
		//建立数据的输入通道。
		FileReader fileReader = new FileReader(file);
		//建立缓冲输入字符流
		BufferedReader bufferedReader = new BufferedReader(fileReader);
		//读取数据
		/*int content = bufferedReader.read();  //读到了一个字符。 读取到的字符肯定也是从Bufferedreader内部的字符数组中获取的到。所以效率高。
		System.out.println((char)content);*/
		//使用BUfferedReader拓展的功能,readLine()  一次读取一行文本,如果读到了文件的末尾返回null表示。
		String line =  null;
		while((line = bufferedReader.readLine())!=null){ // 虽然readLine每次读取一行数据,但是但会的line是不包含\r\n的、
			System.out.println(Arrays.toString("aaa".getBytes()));
		}
		//关闭资源
		bufferedReader.close();
	}
}
           

5. 缓冲输出字符流

输出字符流

----------| Writer  所有输出字符流的基类, 抽象类。

--------------- | FileWriter向文件输出字符数据的输出字符流。

----------------|BufferedWriter 缓冲输出字符流        

缓冲输出字符流作用: 提高FileWriter的写数据效率与拓展FileWriter的功能。

BufferedWriter内部只不过是提供了一个8192长度的字符数组作为缓冲区而已,拓展了FileWriter的功能。

BufferedWriter如何使用?

   1. 找到目标文件

   2. 建立数据的输出通道

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
public class Demo2 {
	public static void main(String[] args) throws IOException {
		//找到目标文件
		File file = new File("F:\\a.txt");
		//建立数据的输出通道
		FileWriter fileWriter = new FileWriter(file,true);
		//建立缓冲输出流对象
		BufferedWriter bufferedWriter = new BufferedWriter(fileWriter); 
		//写出数据
//		bufferedWriter.newLine(); //newLine() 换行。 实际上就是想文件输出\r\n.
		bufferedWriter.write("\r\n");
		bufferedWriter.write("前两天李克强来萝岗!!");
		//关闭资源
		bufferedWriter.flush();
//		bufferedWriter.close();
		
	}
}
           

6.缓冲输入输出字符流登录

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

import java.util.Scanner;
public class Login {
    static Scanner scanner = new Scanner(System.in);

    public static void main(String[] args) throws IOException {
        while (true) {
            System.out.println("请选择功能: A(注册)   B(登陆)");

            String option = scanner.next();
            if ("a".equalsIgnoreCase(option)) {
                //注册
                reg();
            } else if ("b".equalsIgnoreCase(option)) {
                //登陆
                login();
            } else {
                System.out.println("你的输入有误,请重新输入...");
            }
        }
    }
    //登陆
    public static void login() throws IOException {
        System.out.println("请输入用户名:");

        String userName = scanner.next();
        System.out.println("请 输入密码:");

        String password = scanner.next();
        String info = userName + " " + password;
        //读取文件的信息,查看是否有该用户的信息存在,如果存在则登陆成功。
        //建立数据的输入通道
        //建立缓冲输入字符流
        BufferedReader bufferedReader = new BufferedReader(new FileReader(
                    "F:\\users.txt"));
        String line = null;
        boolean isLogin = false; // 用于记录是否登陆成功的标识, 默认是登陆失败的。
//不断的读取文件的内容
        while ((line = bufferedReader.readLine()) != null) {
            if (info.equals(line)) {
                isLogin = true;
                break;
            }
        }
        if (isLogin) {
            System.out.println("欢迎" + userName + "登陆成功...");
        } else {
            System.out.println("不存在该用户信息,请注册!!");
        }
    }
    //注册
    public static void reg() throws IOException {
        System.out.println("请输入用户名:");
        String userName = scanner.next();
        System.out.println("请 输入密码:");
        String password = scanner.next();
        String info = userName + " " + password;
        //把用户的注册的信息写到文件上
        File file = new File("F:\\users.txt");
        FileWriter fileWriter = new FileWriter(file, true);

        //建立缓冲输出字符流
        BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
        //把用户信息写出
        bufferedWriter.write(info);
        bufferedWriter.newLine();
        //关闭资源
        bufferedWriter.close();
    }
}
           

7.装饰者模式1

装饰者设计模式:增强一个类的功能,而且还可以让这些装饰类互相装饰。

 BufferedReader是不是拓展了FileReader的功能。

 BuferedWriter 也是拓展了FileWriter的功能。

 需求1: 编写一个类拓展BufferedReader的功能,增强readLine方法返回 的字符串带有行号。

  需求2:编写一个类拓展BufferedReader的功能,增强readLine方法返回 的字符串带有分号。

  需求3: 编写一个类拓展BufferedReader的功能,增强readLine方法返回 的字符串带有双引号。

需求4: 编写一个类拓展BufferedReader的功能, 增强readLine方法返回 的字符串带有行号+ 分号。

需求5: 编写一个类拓展BufferedReader的功能, 增强readLine方法返回 的字符串带有分号+ 双引号。

 需求6: 编写一个类拓展BufferedReader的功能,增强readLine方法返回 的字符串带有双引号+ 行号。

需求7: 编写一个类拓展BufferedReader的功能, 增强readLine方法返回 的字符串带有行号+ 分号+双引号。

----| Reader

-----------| BufferedReader

---------------|BufferedLineNum  带行号

---------------|BufferedSemi    带分号

---------------|BufferedQuto   带双引

---------------| 子类..

---------------|

增强一个类的功能时候我们可以选择使用继承:

   通过继承实现增强一个类的功能优点:   代码结构清晰,通俗易懂。

   缺点: 使用不灵活,会导致继承的体系过于庞大。

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;

class BufferedLineNum extends BufferedReader {
    //行号
    int count = 1;

    public BufferedLineNum(Reader in) {
        super(in);
    }

    @Override
    public String readLine() throws IOException {
        String line = super.readLine();

        if (line == null) {
            return null;
        }

        line = count + " " + line;
        count++;

        return line;
    }
}


//带分号的缓冲输入字符流
class BufferedSemi extends BufferedReader {
    public BufferedSemi(Reader in) {
        super(in);
    }

    @Override
    public String readLine() throws IOException {
        String line = super.readLine();

        if (line == null) {
            return null;
        }

        line = line + ";";

        return line;
    }
}


//带双引号的缓冲输入字符流
class BufferedQuto extends BufferedReader {
    public BufferedQuto(Reader in) {
        super(in);
    }

    @Override
    public String readLine() throws IOException {
        String line = super.readLine();

        if (line == null) {
            return null;
        }

        line = "\"" + line + "\"";

        return line;
    }
}


public class Demo1 {
    public static void main(String[] args) throws IOException {
        File file = new File("F:\\Demo1.java");

        //建立数据的输入通道
        FileReader fileReader = new FileReader(file);

        //建立带行号的缓冲输入字符流
        BufferedLineNum bufferedLineNum = new BufferedLineNum(fileReader);

        //带有分号的缓冲输入字符流
        BufferedSemi bufferedSemi = new BufferedSemi(fileReader);

        //带有双引号的缓冲输入字符流
        BufferedQuto bufferedQuto = new BufferedQuto(fileReader);

        String line = null;

        while ((line = bufferedQuto.readLine()) != null) {
            System.out.println(line);
        }
    }
}
           
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
/*
装饰者设计模式:增强一个类的功能,而且还可以让这些装饰类互相装饰。

装饰者设计模式的步骤:
        1. 在装饰类的内部维护一个被装饰类的引用。
        2. 让装饰类有一个共同的父类或者是父接口。
继承实现的增强类和修饰模式实现的增强类有何区别?
        继承实现的增强类:
                优点:代码结构清晰,而且实现简单.
                缺点:对于每一个的需要增强的类都要创建具体的子类来帮助其增强,这样会导致继承体系过于庞大。
修饰模式实现的增强类:
                优点:内部可以通过多态技术对多个需要增强的类进行增强, 可以是这些装饰类达到互相装饰的效果。使用比较灵活。
                缺点:需要内部通过多态技术维护需要被增强的类的实例。进而使得代码稍微复杂。
*/
import java.io.IOException;

//带行号的缓冲输入字符流
class BufferedLineNum2 extends BufferedReader {
    //在内部维护一个被装饰类的引用。
    BufferedReader bufferedReader;
    int count = 1;

    public BufferedLineNum2(BufferedReader bufferedReader) {
        super(bufferedReader); // 注意: 该语句没有任何的作用,只不过是为了让代码不报错。
        this.bufferedReader = bufferedReader;
    }

    public String readLine() throws IOException {
        String line = bufferedReader.readLine();

        if (line == null) {
            return null;
        }

        line = count + " " + line;
        count++;

        return line;
    }
}
//带分号缓冲输入字符流
class BufferedSemi2 extends BufferedReader { //为什么要继承?  是为了让这些装饰类的对象可以作为参数进行传递,达到互相装饰 的效果。

    //在内部维护一个被装饰类的引用。
    BufferedReader bufferedReader;

    public BufferedSemi2(BufferedReader bufferedReader) { // new BuffereLineNum();
        super(bufferedReader); // 注意: 该语句没有任何的作用,只不过是为了让代码不报错。
        this.bufferedReader = bufferedReader;
    }

    public String readLine() throws IOException {
        String line = bufferedReader.readLine(); //如果这里的ReadLine方法是调用了buffereLineNum的readLine方法,问题马上解决。
        if (line == null) {
            return null;
        }
        line = line + ";";
        return line;
    }
}

//缓冲类带双引号
class BufferedQuto2 extends BufferedReader {
    //在内部维护一个被装饰的类
    BufferedReader bufferedReader;

    public BufferedQuto2(BufferedReader bufferedReader) { //new  BufferedSemi2();
        super(bufferedReader); //只是为了让代码不报错..
        this.bufferedReader = bufferedReader;
    }

    public String readLine() throws IOException {
        String line = bufferedReader.readLine(); //如果这里的ReadLine方法是调用了buffereLineNum的readLine方法,问题马上解决。
        if (line == null) {
            return null;
        }
        line = "\"" + line + "\"";
        return line;
    }
}
public class Demo2 {
    public static void main(String[] args) throws IOException {
        File file = new File("F:\\Demo1.java");
        FileReader fileReader = new FileReader(file);

        //建立缓冲输入字符流
        BufferedReader bufferedReader = new BufferedReader(fileReader);

        //建立带行号的缓冲输入字符流
        BufferedLineNum2 bufferedLineNum = new BufferedLineNum2(bufferedReader);

        //带分号的缓冲输入字符流
        BufferedSemi2 bufferedSemi2 = new BufferedSemi2(bufferedLineNum);

        //带双引号的缓冲输入字符流
        BufferedQuto2 bufferedQuto2 = new BufferedQuto2(bufferedSemi2);

        String line = null;

        while ((line = bufferedQuto2.readLine()) != null) {
            System.out.println(line);
        }
    }
}
           

8. 装饰者设计模式的作业

一家三口每个人都会工作,儿子的工作就是画画,母亲的工作就是在儿子的基础上做一个增强,不单止可以画画,还可以上涂料。

        爸爸的工作就是在妈妈基础上做了增强,就是上画框。

interface Work {
    public void work();
}
class Son implements Work {
    @Override
    public void work() {
        System.out.println("画画...");
    }
}

class Mather implements Work {
    //需要被增强的类。
    Work worker;

    public Mather(Work worker) {
        this.worker = worker;
    }

    @Override
    public void work() {
        worker.work();
        System.out.println("给画上颜色..");
    }
}


class Father implements Work {
    //需要被增强的类的引用
    Work worker;

    public Father(Work worker) {
        this.worker = worker;
    }

    @Override
    public void work() {
        worker.work();
        System.out.println("上画框...");
    }
}


public class Demo3 {
    public static void main(String[] args) {
        Son s = new Son();

        //		s.work();
        Mather m = new Mather(s);

        //		m.work();
        Father f = new Father(s);
        f.work();
    }
}
           

继续阅读