JavaSE-21- IO流- 文件操作 ,BufferedWriter BufferReader 缓冲区 17自定义缓冲区 装饰设计模式 LineNumberReader

文件操作练习

1.文件复制图解:通过 buf 缓冲区 两个字符流建立联系。

 2. 将E 盘文件复制到D盘:

package day21;
import java.io.*;
public class FileDemo {
    private static    int BUF_SIZE=1024;
    public static void main(String[] args) {
     test1();
     //test2();
    }
    /**
     * 需求:把 E盘的文件复制到D盘
     * 1.需要
     * 读取源。
     * 2.将读取的数据写入目的地。
     * 3.使用字符流
     *
     * 步骤:
     * 1.读取已知文本文件。使用字符和文件关联。
     * FileReadear fr =new  FileReader ("IO_文件.txt");
     * 2.创建一个目标
     * FileWriter fw= new  FileWriter("copytext_1.txt");
     * 3.频繁的读写操作。
     * int ch=0;
     * 方式1
     * while(ch=(fr.read())!=-1){
     *
     * }
     * 方式2:效率高
     * while((len=fw.read(buf))=-1)
     * 4.关闭流
     *
     */
    public static void   test1(){
       int  ch=0;    //1.
        FileReader fr=null;
        FileWriter  fw=null;
        try{
        fr = new  FileReader("E:\\java\\20190420_1\\test1.txt");//E:\java\20190420_1
        fw = new  FileWriter("D:\\test1.txt");
        while((ch =fr.read())!=-1){
            fw.write(ch);
        }
    }catch ( IOException  e) {
        e.getMessage();
    } finally {
        try{
            if(fr!=null){
                fr.close();
            }

        } catch (IOException  e)
        {
            e.printStackTrace();
        }
        try{
           if(fw!=null){
               fw.close();
           }
        }catch (IOException e){
            e.printStackTrace();
        }

    }
    //2.
    //3.

    }

    public static void   test2(){
        int  len=0;    //1.读取的长度
        FileReader fr=null;
        FileWriter  fw=null;
        try{
            fr = new  FileReader("E:\\java\\20190420_1\\test1.txt");//E:\java\20190420_1
            fw = new  FileWriter("D:\\test3.txt");
            char[]  buf  =new char[BUF_SIZE];// 不建议写成char[1024*4] 会做运算
            while((len =fr.read(buf))!=-1){

            }
            fw.write(buf,0,len);
        }catch ( IOException  e) {
            e.getMessage();
            throw  new  RuntimeException(" 文件读取失败");
        } finally {
            try{
                fw.close();// 没做关流操作的话这个文件删不掉。
                fr.close();

            } catch (IOException  e)
            {
                e.printStackTrace();
            }
        }
        //2.
        //3.

    }
}

BufferedReader ,BufferedWriter  字符流缓冲区 

字符流的缓冲区,缓冲区的出现提高了对数据的读写效率。对应类 • BufferedWriter • BufferedReader缓冲区要结合流才可以使用。在流的基础上对流的功能进行了增强。

 

 

private static final String LINE_SEPARATOR = System.getProperty("line.separator");

public void newLine()
throws IOException写一行行分隔符。 行分隔符字符串由系统属性line.separator定义,并不一定是单个换行符('\ n')字符。 
异常 
IOException - 如果发生I / O错误

 

    public static  void  bufferwriter(){
        String  seperator =System.getProperty("line.separator");// 行分隔符字符串由系统属性line.separator定义
      try{
          FileWriter fw = new FileWriter ("bufferwriter.txt");

          BufferedWriter  bw =new BufferedWriter(fw);
          // 接下来使用缓冲区的write   flush  close
          bw.write("aaaaa\r\naaadzzzz");
          bw.write("ddddd"+seperator+"ddddddd");
          for(int i=0;i<10;i++){
              bw.newLine();// 换行
              bw.write("aafffffff");
              bw.flush();
          }

          bw.flush();
          // close 的操作实际是内部是fw 的close 操作。buffedwriter 只是起到了缓冲作用。提高效率。
          bw.close();
      }  catch (IOException  e ){
          e.printStackTrace();
      }
    }

BufferedReader :  可以读一行

 

 demo:

    public static  void  bufferedreader(){
        FileReader fr=null;
        BufferedReader bf = null;
      String  str=null;
        try{
            fr = new FileReader("bufferedwriter.txt");
            bf = new BufferedReader(fr);
            try{
                while((str=bf.readLine())!=null){//public String readLine()
                 System.out.println(str);

                }
            }catch (IOException e){
                e.printStackTrace();
            }



      }  catch ( FileNotFoundException e){
            e.printStackTrace();
        }
        finally{
            try{
                if(bf!=null){
                    bf.close();
                }
            }catch ( IOException e ){
                e.printStackTrace();
            }

        }
    }

这个方法的原理是什么?

练习:利用缓冲区 文件复制

public  static void bufferedWriteAndBufferedReader(){
        FileReader  fr=null;
        BufferedReader br=null;
        FileWriter  fw = null;
        BufferedWriter  bw= null;
        String  filename ="bufferedwriter.txt";
        String    file_write="file_write.txt";
        String  len =null;
        try{
            fr= new FileReader(filename);
            br= new BufferedReader(fr);
          try{

              fw= new FileWriter(file_write);

              bw= new BufferedWriter(fw);
              while ((len=br.readLine())!=null    ){
                  bw.write(len);
                  bw.newLine();//换行
                  bw.flush();
              }
          }  catch ( IOException e){

          }


        }catch ( FileNotFoundException e){

            e.printStackTrace();
        }
        finally {
            try{
                if(bw!=null){
                    bw.close();
                }
            }catch ( IOException e){
                e.printStackTrace();
            }
            try{
                if(br!=null){
                    br.close();
                }
            }catch ( IOException  e){
            }
        }
    }

 

自定义 MyBufferedReader:

package day21;

import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.util.Arrays;
/***
 * 缓冲原理:从源中获取一批数据,装入缓冲区
 * 从缓冲区取出一个个数据,数据取完再获取一批。直到数据取完返回-1;
 */
public class MyBufferedReader   extends Reader {
    private   Reader  reader ;
    private int pos=0;//定义一个指针操作数组元素,
    private  char[] buf =new  char[1024];//定义一个数组作为缓冲区
    private   int count =0;// 元素个数
    public  MyBufferedReader(FileReader  fileReader){
         this.reader= fileReader;
          count=0;
          pos=0;

    }
    @Override
    public void close() throws IOException {
        reader.close();
    }

    @Override
    public int read(char[] chars, int i, int i1) throws IOException {



        return 0;
    }
    public  int myread(){//有问题
         if(count>=0){
             if(count==0){
                 try{
                     int  len=  reader.read(buf);
               //     System.out.println("len ="+len);
                     pos=0;
                     if(len==-1){
                         return  -1;
                     }else{
                         count=len;
                     }
                 }catch ( IOException e){
                     e.printStackTrace();
                 }
             }
             count--;
          //   System.out.println("pos ="+pos+" buf "+buf[pos]);
            char  ch= buf[pos++];
           return ch ;
         }

         return  -1;
    }

    /****
     * 需求:读取一行,
     * 思路:
     * @return
     */

    public String   readLine()throws  IOException{
      StringBuilder   sb= new StringBuilder();
      int  ch=0;
        while((ch=myread())!=-1){

          //  if(buf[pos]=='\r')//不应该 使用 pos  写成buf[pos ]会丢失 一个字符  因为 里面已经当处在 '\r'前一个 字符ch , pos++
                // 已经指向‘\r’ ,这个字不会被添加到 sb
            if(ch=='\r')
            {
               // System.out.println("-----");
                continue;
            }
            if(ch=='\n'){

                return   sb.toString();//123 \r \n  a22222222baqqqqqqqqqqcaeeeeeeeeeeeeeeeeedaeeeeeeeeeeeeef
            }
           sb.append((char) ch);//如果最后的没有回车 被删除了。这时不会进入 ch=='\n'  ,最后一串会丢失
            //  在while 外做判断 字符串不为空就返回保证最后一串返回
      }
        if(sb.length()!=0){
            return sb.toString();
        }
        return   null;
    }
    /**
     * 该方法从缓冲区中一次取一个字符。
     * @return
     * @throws IOException
     */
    public int myRead() throws IOException{

        if(count==0){//一个数据
                count = reader.read(buf);
            pos = 0;
        }
        if(count<0)
            return -1;

        char ch = buf[pos++];

        count--;

        return ch;

		/*
		//1,从源中获取一批数据到缓冲区中。需要先做判断,只有计数器为0时,才需要从源中获取数据。
		if(count==0){
			count = r.read(buf);

			if(count<0)
				return -1;

			//每次获取数据到缓冲区后,角标归零.
			pos = 0;
			char ch = buf[pos];

			pos++;
			count--;

			return ch;

		}else if(count>0){

			char ch = buf[pos];

			pos++;
			count--;

			return ch;

		}*/

    }
}

 

package cn.itcast.p4.io.charstream.mybuffer;

import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;

/**
 * 自定义的读取缓冲区。其实就是模拟一个BufferedReader.
 * 
 * 分析:
 * 缓冲区中无非就是封装了一个数组,
 * 并对外提供了更多的方法对数组进行访问。
 * 其实这些方法最终操作的都是数组的角标。
 * 
 * 缓冲的原理:
 * 其实就是从源中获取一批数据装进缓冲区中。
 * 在从缓冲区中不断的取出一个一个数据。
 * 
 * 在此次取完后,在从源中继续取一批数据进缓冲区。
 * 当源中的数据取光时,用-1作为结束标记。 
 * 
 * 
 * @author Administrator
 *
 */
public class MyBufferedReader extends Reader {

	private Reader r;
	
	//定义一个数组作为缓冲区。
	private char[] buf = new char[1024];
	
	//定义一个指针用于操作这个数组中的元素。当操作到最后一个元素后,指针应该归零。	
	private int pos = 0;	
	
	
	//定义一个计数器用于记录缓冲区中的数据个数。 当该数据减到0,就从源中继续获取数据到缓冲区中。
	private int count = 0;
	
	
	MyBufferedReader(Reader r){
		this.r = r;
	}
	
	/**
	 * 该方法从缓冲区中一次取一个字符。 
	 * @return
	 * @throws IOException
	 */
	public int myRead() throws IOException{
		
		if(count==0){一个数据
			count = r.read(buf);
			pos = 0;
		}
		if(count<0)
			return -1;
		
		char ch = buf[pos++];
		
		count--;
		
		return ch;
		
		/*
		//1,从源中获取一批数据到缓冲区中。需要先做判断,只有计数器为0时,才需要从源中获取数据。
		if(count==0){
			count = r.read(buf);
			
			if(count<0)
				return -1;
			
			//每次获取数据到缓冲区后,角标归零.
			pos = 0;
			char ch = buf[pos];
			
			pos++;
			count--;
			
			return ch;
			
		}else if(count>0){
			
			char ch = buf[pos];
			
			pos++;
			count--;
			
			return ch;
			
		}*/
		
	}
	
	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 {
		
		r.close();
	}

	@Override
	public int read(char[] cbuf, int off, int len) throws IOException {
		
		return 0;
	}

	@Override
	public void close() throws IOException {
	}
}

 

 装饰设计模式;

BufferedReader ,BufferedWriter  是使用了装饰设计模式,对FileReader,FileWriter 装饰。增强效率。

装饰的与继承 有什么区别?

对一组对象的功能进行增强时,就可以使用该模式进行问题的解决。 
    

装饰和继承都能实现一样的特点:进行功能的扩展增强。 

有什么区别呢?

首先有一个继承体系。
Writer
    |--TextWriter:用于操作文本
    |--MediaWriter:用于操作媒体。
    
想要对操作的动作进行效率的提高。
按照面向对象,可以通过继承对具体的进行功能的扩展。 
效率提高需要加入缓冲技术。
    
Writer
    |--TextWriter:用于操作文本
        |--BufferTextWriter:加入了缓冲技术的操作文本的对象。
    |--MediaWriter:用于操作媒体。
        |--BufferMediaWriter:

到这里就哦了。但是这样做好像并不理想。
如果这个体系进行功能扩展,有多了流对象。
那么这个流要提高效率,是不是也要产生子类呢?是。这时就会发现只为提高功能,进行的继承,
导致继承体系越来越臃肿。不够灵活。 

重新思考这个问题?
既然加入的都是同一种技术--缓冲。
前一种是让缓冲和具体的对象相结合。 
可不可以将缓冲进行单独的封装,哪个对象需要缓冲就将哪个对象和缓冲关联。

class Buffer{
    Buffer(TextWriter w)//缓冲 TextWriter 
    {}
    
    Buffer(MediaWriter w)//缓冲 MediaWriter
    {
    
    }
}
class BufferWriter extends Writer{//本身是继承 Writer
    BufferWriter(Writer w)
    {
    }
}
Writer
    |--TextWriter:用于操作文本
    |--MediaWriter:用于操作媒体。
    |--BufferWriter:用于提高效率。
    
装饰比继承灵活。

特点:装饰类和被装饰类都必须所属同一个接口或者父类。 

package cn.itcast.p5.wrapper;
public class PersonDemo {
	/**
	 * @param args
	 */
	public static void main(String[] args) {

		Person p = new Person();
//		p.chifan();
		
		NewPerson p1 = new NewPerson(p);
		p1.chifan();
		
		NewPerson2 p2 = new NewPerson2();
		p2.chifan();
	}

}

class Person{
	void chifan(){
		System.out.println("吃饭");
	}
}
//这个类的出现是为了增强Person而出现的。
class NewPerson{
	private Person p ;
	NewPerson(Person p){
		this.p = p;
	}
	
	public void chifan(){
		System.out.println("开胃酒");
		p.chifan();//不要随便修改原代码
		System.out.println("甜点");
		
	}

}

class NewPerson2 extends Person{
	public void chifan(){
		System.out.println("开胃酒");
		super.chifan();
		System.out.println("甜点");
	}
}

 

  LineNumReader : 

是继承BufferedReader :

例子:

package day21;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.LineNumberReader;
public class LineNumberDemo {
    public static void main(String[] args) {
       lineNumber();
    }
    public  static  void lineNumber(){
        FileReader  fr;
        LineNumberReader  lineNumberReader;
        try{
            fr = new FileReader("test2.txt");
            lineNumberReader= new LineNumberReader(fr);
            try{
                String  str=null;
                lineNumberReader.setLineNumber(3);
                while(   (     str=   lineNumberReader.readLine())!=null) {
                    System.out.println(str + " 行号" + lineNumberReader.getLineNumber());
                }
            }catch (IOException e){
                e.printStackTrace();
            }
        }catch ( FileNotFoundException  e){
            e.printStackTrace();
        }
    }
}
/***
 123 行号1
 sssssssss 行号2
 a22222222b 行号3
 aqqqqqqqqqqc 行号4
 aeeeeeeeeeeeeeeeeed 行号5
 aeeeeeeeeeeeeef 行号6


  调用 set   3后 ,只会影响 get 的行号


 123 行号4
 sssssssss 行号5
 a22222222b 行号6
 aqqqqqqqqqqc 行号7
 aeeeeeeeeeeeeeeeeed 行号8
 aeeeeeeeeeeeeef 行号9

 */

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值