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();
- }
- }