首页 > 代码库 > JAVA学习第四十九课 — IO流(三):缓冲区2 & 装饰设计模式

JAVA学习第四十九课 — IO流(三):缓冲区2 & 装饰设计模式

一、模拟BufferedReader

自定义MyBuffereaReader

对于缓冲区而言,里面其实就是封装一个数组,对外提供方法对数组的操作,这些方法最终操作的都是数组的角标

原理:从源中取出数据存入缓冲区,再从缓冲区不断的取出数据,取完后,继续从源中继续取数据,进缓冲区,直至源中的数据取完,用-1做为结束标记

import java.io.*;
class MyBufferedReader {
	private FileReader fr;
	
	//定义数组作为缓冲区
	private char[] ch = new char[1024];
	//定义一个指针用于对数组的操作,当操作数组的最后一个元素后,指针归零
	private int pos = 0;
	//定义一个计数器,当缓冲区的数据减至0后,继续从源中取数据加到缓冲区中
	private int count = 0;
	
	MyBufferedReader(FileReader fr) {
		this.fr = fr;
	}
	public int Myread() throws IOException{
		//从源中获取一批数据到缓冲区中,先判断count是否是0
		if(count==0) {
			count = fr.read(ch);
			pos = 0;
		}
			if (count<0)  
				return -1;
			
			char temp = ch[pos++];
			count--;
			return temp;
	}
	public String MyReadLine() throws IOException{
		
		//将读取的数据存储到缓冲区中
		StringBuilder sb = new StringBuilder();
		int ch = 0;
		while((ch = Myread())!=-1){
		
			if(ch=='\r')
				continue;
			if(ch=='\n')
				return sb.toString();
			
			sb.append((char)ch);
		}
		if(sb.length()!=0)
			return sb.toString();
		return null;
	}
	public void myClose() throws IOException{
		fr.close();
	}
}
public class Main 
{
	public static void main(String[] args) throws IOException {
	
		FileReader fr = new FileReader("ACM.txt");
		MyBufferedReader msb = new MyBufferedReader(fr);
		
		String str = null;
		
	while((str = msb.MyReadLine())!=null){

			System.out.println(str);
		}
		msb.myClose();

	}
}


二、装饰设计模式

当对一组对象的功能进行增强时,就可以使用该模式进行问题的解决,上述的自定义MyBufferedReader类就是很好的体现,对于FileReader类比原来的功能简便,当然上述代码写的比较简单

class Room{
	public void show(){
		System.out.println("房子");
	} 
}
class NewRoom 
{
	private Room or;
	public NewRoom(OldRoom or) {
		// TODO Auto-generated constructor stub
		this.or = or;
	}
	public void show(){
		or.show();
		System.out.println("平房");
	}
}

一定要避免的是修改源代码,当然继承也可以实现功能的增强。

但是继承的话,会让继承体系复杂且麻烦


装饰设计模式和继承的区别:

继承:如果为了增强功能,就要继续写子类,只是为了一个新的NewRoom,就要创建一个子类,NewRoom后出现别墅呢,又要创建子类,逐渐的,导致继承体系越来越臃肿

装饰设计模式:无论NewRoom还是别墅,都是Room的一种,都保持着房子的基本属性

所以,利用装饰设计模式,只需要把被装饰的对象传入即可,可以将缓冲技术单独抽取进行封装,要缓冲区谁将谁和缓冲相关联即可,这样的设计的相对体系会变的简单。


三、LineNumberReader

API文档解释:跟踪行号的缓冲字符输入流。此类定义了方法setLineNumber(int)getLineNumber(),它们可分别用于设置和获取当前行号。

import java.io.*;

public class Main 
{
	public static void main(String[] args) throws IOException {
	
		FileReader fr = new FileReader("ACM.txt");
		LineNumberReader lr = new LineNumberReader(fr);
		
		String str = null;
		
		lr.setLineNumber(10);//设置行号从10开始
		while((str = lr.readLine())!=null){
			System.out.println(str+" line : "+lr.getLineNumber());
		}	
		lr.close();
	}
}

此类用的地方不是很多,知道怎么用即可。


四、练习

一定要用字节流文件复制媒体文件

import java.io.*;

public class Main 
{
	public static void main(String[] args) throws IOException {
		//copy_mp3_1();
		//copy_mp3_2();//开发建议使用这种
		copy_mp3_3();
	}

	public static void copy_mp3_3() throws IOException {
		// TODO Auto-generated method stub
		FileInputStream fis = new FileInputStream("D:\\盛夏光年.mp3");
		FileOutputStream fos = new FileOutputStream("D:\\盛夏光年3.mp3");
		
		byte[] by = new byte[fis.available()];//局限:文件过大,就不行了
	
		fis.read(by);
		fos.write(by);
	
		fos.close();
		fis.close();
	}

	public static void copy_mp3_2() throws IOException {
		// TODO Auto-generated method stub
		FileInputStream fis = new FileInputStream("D:\\盛夏光年.mp3");
		BufferedInputStream br = new BufferedInputStream(fis);
		
		FileOutputStream fos = new FileOutputStream("D:\\盛夏光年2.mp3");
		BufferedOutputStream bw = new BufferedOutputStream(fos);
		
		int len = 0;
		while((len = br.read())!=-1){
				bw.write(len);
				bw.flush();
		}
		br.close();
		bw.close();
	}

	public static void copy_mp3_1() throws IOException {
		// TODO Auto-generated method stub
		FileInputStream fis = new FileInputStream("D:\\盛夏光年.mp3");
		FileOutputStream fos = new FileOutputStream("D:\\盛夏光年1.mp3");
		
		byte[] by = new byte[1024];//注意Mp3文件的字节数,这个数组越接近效率越块
		int len = 0;
		while((len = fis.read(by))!=-1){
				fos.write(len);
				fos.flush();
		}
		fos.close();
		fis.close();
	}
}

JAVA学习第四十九课 — IO流(三):缓冲区2 & 装饰设计模式