天天看點

Java基礎之IO流知識點總結二

位元組流的緩沖區
緩沖區的出現提高了對流的操作效率。
原理:其實就是将數組進行封裝。
對應的對象:
   BufferedWriter:
      特有方法:newLine():跨平台的換行符。
   BufferedReader:
        特有方法:readLine():一次讀取一行,到行标記時,将行标記之前的字元資料作為字元串傳回。當讀到末尾時,傳回full。
在使用緩沖區對象時,要明确,緩沖的存在是為了增強流的功能而存在,是以在建立緩沖區對象時,要先有流對象的存在。
其實緩沖區内部就是在使用流對象的方法,隻不過加入了數組對資料進行了臨時存儲,為了提高操作資料的效率。
代碼上的展現:
寫入緩沖區對象。
//建立緩沖區對象必須把流對象作為參數傳遞給緩沖區的構造函數。
BufferedWriter bw = new BufferedWriter(newFileWriter(“buf.txt”));
//将資料寫入到了緩沖區
bw.writer(“itheima”);
//對緩沖區的資料進行重新整理,将資料刷到目的地
bw.flush();
//關閉緩沖區,其實是關閉了被包裝在内部的流對象。
bw.close();      
例子1:利用位元組流的緩沖區将資料寫入到一個文本檔案中。      
package cn.itheima.day03;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
/**
 * 緩沖區的出現時為了提高流的操作效率而出現的。
 * 是以,在建立緩沖區是必須先有流對象。
 * @author wl-pc
*/
public class BufferedWriterDemo {
	public static void main(String[] args) {
		FileWriter fw=null;
		BufferedWriter bw=null;
		try {
			//1.建立一個字元寫入流對象
		    fw = new FileWriter("F:\\Javajichu\\JavaLianXi\\src\\cn\\itheima\\day03\\buf.txt");
			//為了提高字元的寫入流效率,加入了緩沖技術,隻要将需要提
			//高效率的流對象作為參數傳遞給緩沖區的構造函數即可
			bw = new BufferedWriter(fw);
			for(int x = 0; x < 5; x++ ){
				bw.write("itheima"+x+",helloworld!");
				bw.newLine();   //跨平台的換行
				//記住:隻要用到緩沖區就需要重新整理
				bw.flush();
			}	
		} catch (IOException e) {
			System.out.println(e.toString());
		} finally{
			if(bw!=null){
				try {
					//關閉緩沖區的流對象其實關閉的是緩沖區中的寫入流對象
					//是以在這裡隻需要關閉緩沖區流即可
					fw.close();
				} catch (IOException e) {
					System.out.println("close:"+e.toString());
				}
			}
		}
	}
}
           
例子2:利用字元讀取流的緩沖區讀取一個.java的檔案顯示到控制台上。      
package cn.itheima.day03;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
/**
 * 字元讀取流的緩沖區
 * 該緩沖區提供了一次讀取一行的方法,友善了對文本資料的擷取。
 * readLine()方法,當傳回空時,表示讀到了檔案的末尾
 * @author wl-pc
*/
public class BufferedReaderDemo {
	public static void main(String[] args) {
		FileReader fr=null;
		BufferedReader br=null;
		try {
			//建立一個讀取流對象,和檔案相關聯
			fr = new FileReader("F:\\Javajichu\\JavaLianXi\\src\\cn\\itheima\\day03\\BufferedWriterDemo.java");
	        //為了提高效率,加入了緩沖技術,将字元讀取流對象傳遞給緩沖對象的構造函數。
			br = new BufferedReader(fr);
			String line=null;
			try {
				while((line = br.readLine())!=null){    //readLine一行一行的讀取資料
					System.out.println(line);
				}
			} catch (IOException e) {
				System.out.println(e.toString());
			}
		} catch (FileNotFoundException e) {
			System.out.println(e.toString());
		}finally{
			if(br!=null){
				try {
					br.close();
				} catch (IOException e) {
					System.out.println("close:"+e.toString());
				}
			}
		}
	}
}
           
例子3:通過緩沖區的方式,對文本檔案進行拷貝。      
package cn.itheima.day03;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
/**
 * 通過緩沖區複制一個*.java的檔案
 * @author wl-pc
 * readLine()方法傳回的時候,隻傳回回車符之前的資料内容,并不傳回回車符。
 */
public class CopyTextByBuf {
	public static void main(String[] args) {
		BufferedReader bufr = null;
		BufferedWriter bufw = null;
			try {
			bufr=new BufferedReader(new FileReader("F:\\Javajichu\\JavaLianXi\\src\\cn\\itheima\\day03\\BufferedWriterDemo.java"));
		     bufw=new BufferedWriter(new FileWriter("F:\\Javajichu\\JavaLianXi\\src\\cn\\itheima\\day03\\BufferedWriter_copy.txt"));
			    String line = null;   //臨時資料的中轉站
			    while((line = bufr.readLine())!=null){
			    	bufw.write(line);
			    	bufw.newLine();   //跨平台換行
			    }	
			} catch (FileNotFoundException e) {
				System.out.println(e.toString());
			} catch (IOException e) {
				System.out.println(e.toString());
			}finally{
				if(bufr!=null){
					try {
						bufr.close();
					} catch (IOException e) {
						System.out.println("close:"+e.toString());
					}
				}
				if(bufw!=null){
					try {
						bufw.close();
					} catch (IOException e) {
						System.out.println("close:"+e.toString());
					}
				}
			}
	  }
}
           
readLine()方法的原理:
其實緩沖區中的readLine()方法,用的還是與緩沖區關聯的流對象的read()方法。隻不過,每一次讀到一個字元,先不進行具體的操作,先進行臨時存儲。當讀到回車标記時,将臨時容器中存儲的資料一次性的傳回。
既然明确了原理,我們也可以實作一個類似的功能方法。      
例子4:自定義一個類中包含一個功能和readLine()一緻的方法來模拟一下BufferedReader      
package cn.itheima.day03;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
/**
 * 明白了BufferedReader類中特有的方法readLine()的原理後,
 * 可以自定義一個類中包含一個功能和readLine()一緻的方法
 * 來模拟一下BufferedReader
 */
class MyBufferedReader{
	private FileReader fr;
	public MyBufferedReader(FileReader fr) {
		this.fr = fr;
	}
	//可以一次讀一行資料的方法
	public String myReaderLine() throws IOException{
        //定義一個臨時容器,原BufferedReader封裝的是字元數組,
		//為了示範友善,定義了一個StringBuilder容器,因為最終還是要将資料變成字元串
		StringBuilder sb = new StringBuilder(); 
		int ch = 0;
			while((ch=fr.read())!=-1){
				if(ch == '\r')
					continue;
				if(ch == '\n')
					return sb.toString();
				else
				    sb.append((char)ch);
			}
			if(sb.length()!=0){
				return sb.toString();
			}
		return null;
	}
	//定義我的關閉流的方法
	public void myClose() throws IOException{	
	    fr.close();
	}
}
//主函數入口點
public class MyBufferedReaderDemo {
	public static void main(String[] args) {
		FileReader fileReader=null;
		MyBufferedReader mbr=null;
		try {
			fileReader = new FileReader("F:\\Javajichu\\JavaLianXi\\src\\cn\\itheima\\day03\\buf.txt");
			mbr = new MyBufferedReader(fileReader);
			String line = null;
			try {
				while((line=mbr.myReaderLine())!=null){
					System.out.println(line);
				}
			} catch (IOException e) {
				System.out.println(e.toString());
			}
		} catch (FileNotFoundException e) {
			System.out.println(e.toString());
		} finally{
			if(mbr!=null){
				try {
					mbr.myClose();
				} catch (IOException e) {
					System.out.println("close:"+e.toString());
				}
			}
		}
	}
}
           
由例子4可以看出:readLine()方法的出現實際上是在增強read()方法的功能,增強的方式是把被增強的對象傳給增強類。這也是一種設計模式:裝飾設計模式。
裝飾設計模式:當想要對已有的對象進行功能增強時,可以定義類,将已有的對象傳入,基于已有的功能,并提供加強功能,那麼自定義的這個類就叫裝飾類。即:對一組對象的功能進行增強時,就可以使用該模式進行問題的解決。裝飾類通常會通過構造方法接收被裝飾的對象,并基于被裝飾的對象的功能,提供更強的功能。      
例子5:定義一個裝飾類的實作      
package cn.itheima.day03;
class Person{
	public void chifan(){
		System.out.println("吃飯");
	}
}
class SuperPerson{
	private Person p;
	SuperPerson(Person p) {
	    this.p = p;
	}
	public void superChifan(){
		System.out.println("開胃酒");
		p.chifan();
		System.out.println("甜點");
		System.out.println("來一根煙");
	}
}
public class PersonDemo {
	public static void main(String[] args) {
		Person p = new Person();
		SuperPerson sp = new SuperPerson(p);
		sp.superChifan();
	}
}
           
裝飾和繼承都能實作一樣的特點:進行功能的擴充增強,但是裝飾比繼承靈活,裝飾的特點:裝飾類和被裝飾類都必須所屬同一個接口或者父類。
下面舉一個例子:
      Writer
          |--MediaWriter
          |--TextWriter
(注意:MediaWriter和TextWriter兩個類在JDK中并不存在,為了是更形象舉例說明而“建立”的,在這裡不要誤解)
需求:想要對資料的操作提高效率,就用到了緩沖技術。
通過所學習的繼承特性。可以建立子類複寫父類中的write方法。即可
 
Witer(注:不要誤解,以下的兩個對象在JDK中是不存在的,隻為舉例說明)
  |-- MediaWriter
         |--BufferedMediaWriter
  |-- TextWriter
         |--BufferedTextWriter
當Writer中子類對象過多,那麼為了提高每一個對象效率,每一個對象都有一個自己的子類Buffered。
雖然可以實作,但是繼承體系變的很臃腫。
 
那麼是否可以對其進行一下優化呢?
其實子類都是在使用緩沖技術。
可不可以對緩沖技術進行描述,将需要增強的對象傳遞給緩沖區即可。
classBufferdWriter{
      BufferedWriter(MediaWritermw){ } 
      BufferedWriter(TextWritermw){ } 
}
但是發現該方法缺點:該類雖然完成了對已有兩個對象的增強。
但是當有新的對象出現時,還要繼續在該類中添加構造函數。這樣不利于擴充和維護。
還有一個方法就是:将對這些對象父類型進行操作即可。這就是多态,提高了程式的擴充性。同時BufferedWriter中一樣具體write方法,隻不過是增強後的write。是以BuferedWriter也應該是Writer中的一個子類。
classBufferedWriter extends Writer{
     private Writer w;
     BufferedWriter(Writer w){
         this.w = w;
     }
}
 
即體系變成如下格式:(變化:從繼承結構變為組合結構)
Writer
     |--MediaWriter
     |--TextWriter
     |--BufferedWriter
這樣就會發現裝飾設計模式,優化增強功能的部分。比繼承要靈活很多。而且降低了類與類之間的關系。
但是要注意:裝飾類因為增強了已有對象,具備的功能和已有的功能是相同的,隻不過提供了更強的功能,是以,裝飾類可被裝飾類通常是都屬于一個體系中的。      
例子6:利用裝飾類定義一個功能readLine()一緻的方法來模拟一下BufferedReader      
package cn.itheima.day03;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
/**
 * 明白了BufferedReader類中特有的方法readLine()的原理後,
 * 可以自定義一個類中包含一個功能和readLine()一緻的方法
 * 來模拟一下BufferedReader
 */
class MyBufferedReader2 extends Reader{
	private Reader fr;
	public MyBufferedReader2(Reader fr) {
		this.fr = fr;
	}
	//可以一次讀一行資料的方法
	public String myReaderLine() throws IOException{
        //定義一個臨時容器,原BufferedReader封裝的是字元數組,
		//為了示範友善,定義了一個StringBuilder容器,因為最終還是要将資料變成字元串
		StringBuilder sb = new StringBuilder(); 
		int ch = 0;
			while((ch=fr.read())!=-1){
				if(ch == '\r')
					continue;
				if(ch == '\n')
					return sb.toString();
				else
				    sb.append((char)ch);
			}
			if(sb.length()!=0){
				return sb.toString();
			}
		return null;
	}
	//定義我的關閉流的方法
	public void myClose() throws IOException{	
	    fr.close();
	}
	@Override
	public void close() throws IOException {
		fr.close();
	}
	@Override
	public int read(char[] cbuf, int off, int len) throws IOException {
		return fr.read(cbuf,off,len);
	}
}
//主函數入口點
public class MyBufferedReaderDemo2 {
	public static void main(String[] args) {
		FileReader fileReader=null;
		MyBufferedReader2 mbr=null;
		try {
			fileReader = new FileReader("F:\\Javajichu\\JavaLianXi\\src\\cn\\itheima\\day03\\buf.txt");
			mbr = new MyBufferedReader2(fileReader);
			String line = null;
			try {
				while((line=mbr.myReaderLine())!=null){
					System.out.println(line);
				}
			} catch (IOException e) {
				System.out.println(e.toString());
			}
		} catch (FileNotFoundException e) {
			System.out.println(e.toString());
		} finally{
			if(mbr!=null){
				try {
					mbr.myClose();
				} catch (IOException e) {
					System.out.println("close:"+e.toString());
				}
			}
		}
	}
}
           
例子7:利用LineNumberReader的 getLineNumber()方法可以的帶行号的輸出文本内容。      
package cn.itheima.day03;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.LineNumberReader;
public class LineNumberReaderDemo {
	public static void main(String[] args) {
		FileReader fr=null;
		LineNumberReader inr=null;
		try {
			fr = new FileReader("F:\\Javajichu\\JavaLianXi\\src\\cn\\itheima\\day03\\PersonDemo.java");
			inr = new LineNumberReader(fr);
			String line = null;
			try {
				while((line=inr.readLine())!=null){
					 //LineNumberReader getLineNumber()方法可以的帶行号的輸出
					System.out.println(inr.getLineNumber()+"::"+line);  
				}
			} catch (IOException e) {
				System.out.println(e.toString());
			}
		} catch (FileNotFoundException e) {
			System.out.println(e.toString());
		} finally{
			if(inr!=null){
				try {
					inr.close();
				} catch (IOException e) {
					System.out.println("close:"+e.toString());
				}
			}
		}
	}
}
           
例子8:利用自定義的MyLineNumberReader的 getLineNumber()方法可以的帶行号的輸出      
package cn.itheima.day03;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
//直接繼承父類,可以複用myReaderLine()方法和myClose()方法。
class MyLineNumberReader extends MyBufferedReader{  
	private int lineNumber;
	public MyLineNumberReader(FileReader fr) {
		super(fr);
	}
	public int getLineNumber() {
		return lineNumber;
	}
	public void setLineNumber(int lineNumber) {
		this.lineNumber = lineNumber;
	}
	public String myReaderLine() throws IOException{
		lineNumber++;
		return super.myReaderLine();
	}
}
public class MyLineNumberReaderDemo {
	public static void main(String[] args) {
		MyLineNumberReader mylnr=null;
		try {
			FileReader fr = new FileReader("F:\\Javajichu\\JavaLianXi\\src\\cn\\itheima\\day03\\BufferedWriterDemo.java");
			mylnr = new MyLineNumberReader(fr);
		} catch (FileNotFoundException e) {
			System.out.println(e.toString());
		}
		String line = null;
		try {
			while((line=mylnr.myReaderLine())!=null){
				System.out.println(mylnr.getLineNumber()+"::"+line);
			}
		} catch (IOException e) {
			System.out.println(e.toString());
		}finally{
			if(mylnr!=null){
				try {
					mylnr.myClose();
				} catch (IOException e) {
					System.out.println("close:"+e.toString());
				}
			}
		}
	}
}
           
目前學習的流對象:
    字元流:
        FileReader
        FileWriter
 
        BufferedReader
        BufferedWriter
 
那麼,我們還要學習位元組流
    位元組流:
        FileInputStream
        FileOutputStream
 
        BufferedInputStream
        BufferedOutputStream
位元組流:
抽象基類: InputStream  OutputStream
位元組流可以操作任何資料。
注意:字元流使用的數組是字元數組。char[] chs
位元組流使用的數組是位元組數組。byte [] bt
主要代碼模式:
FileOutputStreamfos = new FileOutputStream(“a.txt”);
fos.write(“abcdef”);  //直接将資料寫入到了目的地
fos.close();  //隻關閉資源
 
FileInputStreamfis = new FileInputStream("a.txt");
//fis.available();//擷取關聯的檔案的位元組數。
//如果檔案體積不是很大。
//可以這樣操作。
byte[]buf = new byte[fis.available()];//建立一個剛剛好的緩沖區。
//但是這有一個弊端,就是檔案過大,大小超出jvm的内容空間時,會記憶體溢出。
fis.read(buf);
System.out.println(newString(buf));      
例子9:利用位元組流讀取或寫入文本内容到控制台或者文本檔案中      
package cn.itheima.day03;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class FileStream {
	//讀檔案(一個一個的讀,讀一個存一個)
	public static void readFile_1(){
		FileInputStream fis=null;
		try {
			fis = new FileInputStream("F:\\Javajichu\\JavaLianXi\\src\\cn\\itheima\\day03\\fos.txt");
			int ch = 0;
			try {
				while((ch=fis.read())!=-1){
					System.out.print((char)ch);
				}
			} catch (IOException e) {
				System.out.println(e.toString());
			}
		} catch (FileNotFoundException e) {
			System.out.println(e.toString());
		}finally{
			if(fis!=null){
				try {
					fis.close();
				} catch (IOException e) {
					System.out.println("close:"+e.toString());
				}
			}
		}
	}
	//讀方法2(讀完之後,一起存起來)
	public static void readFile_2(){
		FileInputStream fis = null;
		try {
			fis = new FileInputStream("F:\\Javajichu\\JavaLianXi\\src\\cn\\itheima\\day03\\fos.txt");
			byte[] buf = new byte[1024];
			int len = 0;
			while((len=fis.read(buf))!=-1){
				System.out.println(new String(buf,0,len));
			}
		} catch (FileNotFoundException e) {
			System.out.println(e.toString());
		} catch (IOException e) {
			System.out.println(e.toString());
		}finally{
			if(fis!=null){
				try {
					fis.close();
				} catch (IOException e) {
					System.out.println("close:"+e.toString());
				}
			}
		}
	}
	//讀檔案
	public static void readFile_3(){
		FileInputStream fis = null;
	    try {
			fis = new FileInputStream("F:\\Javajichu\\JavaLianXi\\src\\cn\\itheima\\day03\\fos.txt");
			int num = fis.available();  //獲得内容的長度大小
			byte[] buf = new byte[num];  //可以定義一個剛剛好的byte數組(即:剛剛好的緩沖區),它的長度就是num
			int len =fis.read(buf);   //在這裡不用循環了
			System.out.println(new String(buf,0,len));
		
		} catch (FileNotFoundException e) {
			System.out.println(e.toString());
		} catch (IOException e) {
			System.err.println(e.toString());
		}finally{
			if(fis!=null){
				try {
					fis.close();
				} catch (IOException e) {
					System.out.println("close:"+e.toString());
				}
			}
		}
	}
	//寫檔案
	public static void writeFile(){
		FileOutputStream fos=null;
		try {
			fos = new FileOutputStream("F:\\Javajichu\\JavaLianXi\\src\\cn\\itheima\\day03\\fos.txt");
			fos.write("itheima,helloworld!".getBytes());   //位元組流不需要重新整理的,但需要關閉資源
			
		} catch (FileNotFoundException e) {
			System.out.println(e.toString());
		} catch (IOException e) {
			System.out.println(e.toString());
		}finally{
			if(fos!=null){
				try {
					fos.close();
				} catch (IOException e) {
					System.out.println("close:"+e.toString());
				}
			}
		}
	}
	public static void main(String[] args) {
		//writeFile();
		//readFile_1();
		//readFile_2();
		readFile_3();
	}
           
例子10:想要操作圖檔資料,copy一個圖檔到指定位置      
package cn.itheima.day03;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
/**
 * 示範:複制一張圖檔
 * 思路:
 *     1.用位元組讀取流對象和圖檔關聯
 *     2.用位元組寫入流對象建立一個圖檔檔案,用于存儲擷取到的圖檔資料
 *     3.通過循環讀寫,完成資料的存儲
 *     4.關閉資源
 * @author wl-pc
*/
public class CopyPic {
	public static void main(String[] args) {
		FileOutputStream fos =null;
		FileInputStream fis = null;
		try {
			fos = new FileOutputStream("F:\\Javajichu\\JavaLianXi\\src\\cn\\itheima\\day03\\2.jpg");
			fis = new FileInputStream("F:\\Javajichu\\JavaLianXi\\src\\cn\\itheima\\day03\\1.jpg");
			byte[] buf = new byte[1024*4];
			int len = 0;
			while((len=fis.read(buf))!=-1){
				fos.write(buf,0,len);
			}
		} catch (FileNotFoundException e) {
			System.out.println(e.toString());
		} catch (IOException e) {
			System.out.println(e.toString());
		}finally{
			if(fos!=null){
				try {
					fos.close();
				} catch (IOException e) {
					System.out.println("close:"+e.toString());
				}
			}
			if(fis!=null){
				try {
					fis.close();
				} catch (IOException e) {
					System.out.println("close:"+e.toString());
				}
			}
		}
	}
}
           
例子11:示範:mp3複制,通過緩沖區      
package cn.itheima.day03;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
/**
 * 示範:mp3複制,通過緩沖區
 * BufferedOuputStream緩沖輸出流
 * BufferedInputStream緩沖輸入流
 * @author wl-pc
 */
public class CopyMP3 {
	//通過位元組流的緩沖區完成複制
	public static void copy_1(){
		BufferedInputStream bufis=null;
		BufferedOutputStream bufos=null;
		try {
			bufis = new BufferedInputStream(new FileInputStream("F:\\Javajichu\\JavaLianXi\\src\\cn\\itheima\\day03\\0.mp3"));
			bufos = new BufferedOutputStream(new FileOutputStream("F:\\Javajichu\\JavaLianXi\\src\\cn\\itheima\\day03\\1.mp3"));
			int by = 0;
			while((by=bufis.read())!=-1){
				bufos.write(by);
			}
		} catch (FileNotFoundException e) {
			System.out.println(e.toString());
		} catch (IOException e) {
			System.out.println(e.toString());
		}finally{
			if(bufis!=null){
				try {
					bufis.close();
				} catch (IOException e) {
					System.out.println(e.toString());
				}
			}
			if(bufos!=null){
				try {
					bufos.close();
				} catch (IOException e) {
					System.out.println(e.toString());
				}
			}
		}
	}
	//利用自己定義的緩沖區拷貝mp3檔案
	public static void copy_2(){
		MyBufferedInputStream bufis=null;
		BufferedOutputStream bufos=null;
		try {
			bufis=new MyBufferedInputStream(new FileInputStream("F:\\Javajichu\\JavaLianXi\\src\\cn\\itheima\\day03\\0.mp3"));
			bufos=new BufferedOutputStream(new FileOutputStream("F:\\Javajichu\\JavaLianXi\\src\\cn\\itheima\\day03\\2.mp3"));
			int by = 0;
			while((by=bufis.myRead())!=-1){
				bufos.write(by);
			}
		} catch (FileNotFoundException e) {
			System.out.println(e.toString());
		} catch (IOException e) {
			System.out.println(e.toString());
		}finally{
			if(bufis!=null){
				try {
					bufis.myClose();
				} catch (IOException e) {
					System.out.println(e.toString());
				}
			}
			if(bufos!=null){
				try {
					bufos.close();
				} catch (IOException e) {
					System.out.println(e.toString());
				}
			}
		}
	}
	public static void main(String[] args) {
		long start = System.currentTimeMillis();
		//copy_1();
		copy_2();
		long end = System.currentTimeMillis();
		System.out.println((end-start)+"毫秒");
	}
}
           
自定義的讀取mp3的緩沖區代碼:      
package cn.itheima.day03;
import java.io.IOException;
import java.io.InputStream;
class MyBufferedInputStream {
    private InputStream in;
    private byte[] buf = new byte[1024];
    private int pos = 0,count = 0;
    MyBufferedInputStream(InputStream in) {
		this.in = in;
	}
    //一次讀取一個位元組,從緩沖區中(位元組數組中讀取)擷取
    public int myRead() throws IOException{
    	if(count==0){
    		//通過in對象讀取硬碟上的資料存儲到buf中
    		count = in.read(buf);
    		if(count<0){
    			return -1;
    		}
    		pos=0;
    		byte b = buf[pos];
    		count--;
    		pos++;
    		return b&255;
    	}else if (count>0) {
    		byte b = buf[pos];
    		count--;
    		pos++;
    		return b&255;
		}
    	return -1;
    }
    public void  myClose() throws IOException{
    	in.close();
    }
}
           
注意:位元組流的read()方法讀取一個位元組。為什麼傳回的不是byte類型的,而是int 類型的呢?
因為read方法讀到末尾時傳回的是-1.而在所操作的資料中的很容易出現連續多個1的情況,而連續讀到8個1,就是-1.導緻讀取會提前停止。
是以将讀到的一個位元組給提升為一個int類型的數值,但是隻保留原位元組,并在剩餘二進制位補0.
具體操作是:byte&255  or  byte&0xff    
對于write方法,可以一次寫入一個位元組,但接收的是一個int類型數值。隻寫入該int類型的數值的最低一個位元組(8位)。即對于write()方法實際上進行了強制轉化的動作。
簡單說:read方法對讀到的資料進行提升。write對操作的資料進行轉換。      
例子12:讀取鍵盤錄入      
package cn.itheima.day03;
import java.io.IOException;
import java.io.InputStream;
/**
 * 示範:讀取鍵盤錄入
 * System.out對應的是标準的輸出裝置,控制台
 * System.in對應的是标準的輸入裝置,鍵盤
 * @author wl-pc
 *  需求:通過鍵盤錄入資料,當錄入一行的資料後,就
 *        将資料進行列印,如果錄入的資料是over,那麼停止錄入
 */
public class ReadIn {
	public static void main(String[] args) throws IOException {
		/*System.out.println('\r'+0);
		System.out.println('\n'+0);
        InputStream in = System.in;
        int by = in.read();   //read()方法是一個堵塞時方法,沒有讀到資料,它就會等
        System.out.println(by);*/
		InputStream in = System.in;
		StringBuilder sb= new StringBuilder();
		while(true){
			int ch =in.read();
			if(ch=='\r')
				continue;
			if(ch=='\n'){
			    String s = sb.toString();
			    if("over".equals(s)){
			    	break;
			    }
			    System.out.println(s.toUpperCase());
			    sb.delete(0, sb.length());  //清空緩沖區的内容
			}else{
			    sb.append((char)ch);
			}
		}
	}
}
           
通過剛才的鍵盤錄入資料并列印大寫字母,發現其實就是讀一行資料的原理。也就是readLine()的方法。
考慮一個問題:能不能直接使用readLine()方法來完成鍵盤錄入的一行資料的讀取呢?這樣高效些。
readLine()方法是字元流BufferesReader類的方法而鍵盤錄入的方法read()是位元組流InputStream類中的方法
考慮:能不能将位元組流轉成位元組流,再使用字元流緩沖區的readLine()方法呢?
字元流中有一個這樣的轉換流InputStreamReader()方法,可以将位元組流轉換成字元流
轉換流:
   特點:
      1,是位元組流和字元流之間的橋梁。
      2,該流對象中可以對讀取到的位元組資料進行指定編碼表的編碼轉換。
什麼時候使用呢?
     1,當位元組和字元之間有轉換動作時。
     2,流操作的資料需要進行編碼表的指定時。
具體的對象展現:這兩個流對象是字元流體系中的成員。
     1,InputStreamReader:位元組到字元的橋梁。
     2,OutputStreamWriter:字元到位元組的橋梁。
這兩個流對象是字元流體系中的成員。那麼它們有轉換作用,而本身又是字元流。是以在構造的時候,需要傳入位元組流對象進來。
構造函數:
      InputStreamReader(InputStream):通過該構造函數初始化,使用的是本系統預設的編碼表GBK。
      InputStreamReader(InputStream,StringcharSet):通過該構造函數初始化,可以指定編碼表。
      OutputStreamWriter(OutputStream):通過該構造函數初始化,使用的是本系統預設的編碼表GBK。
      OutputStreamWriter(OutputStream,StringcharSet):通過該構造函數初始化,可以指定編碼表。
操作檔案的字元流對象是轉換流的子類。
Reader
  |--InputStreamReader
        |--FileReader
Writer    
  |--OutputStreamWriter
        |--FileWriter
轉換流中的read()方法,已經融入了編碼表中。在底層調用位元組流的read方法時将擷取的一個或者多個位元組資料進行臨時存儲,并去查指定的編碼表,如果編碼表沒有指定,查的是預設碼表。那麼轉流的read方法就可以傳回一個字元比如中文。轉換流已經完成了編碼轉換的動作,對于直接操作的文本檔案的FileReaer而言,就不用在重新定義了,隻要繼承該轉換流,擷取其方法,就可以直接操作文本檔案中的字元資料了。
注意:
在使用FileReader操作文本資料時,該對象使用的是預設的編碼表。如果要使用指定編碼表時,必須使用轉換流。
FileReaderfr = new FileReader(“a.txt”);   //操作a.txt中的資料,使用的是本系統預設的編碼方式GBK。
//操作a.txt中的資料使用的也是本系統預設的編碼方式GBK。
InputStreamReaderisr = new InputStreamReader(new FileInputStream(“a.txt“));
這兩句的代碼意義相同。
但是:如果a.txt中的檔案中的字元資料是通過utf-8的形式編碼。那麼在讀取時,就必須指定編碼表。那麼轉換流必須使用。
InputStreamReader isr = new InputStreamReader(newFileInputStream(“a.txt”),”UTF-8”);      
例子13:将位元組流轉成字元流,再使用字元流緩沖區的readLine()方法讀取一行資訊顯示出來。      
package cn.itheima.day03;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
/**
 * 通過剛才的鍵盤錄入資料并列印大寫字母,發現其實就是讀一行資料的原理。
 * 也就是readLine()的方法
 * 考慮一個問題:能不能直接使用readLine()方法來完成鍵盤錄入的一行資料的讀取呢?這樣高效些。
 * readLine()方法是字元流BufferesReader類的方法
 * 而鍵盤錄入的方法read()是位元組流InputStream類中的方法
 * 考慮:能不能将位元組流轉成位元組流,再使用字元流緩沖區的readLine()方法呢?
 * 字元流中有一個這樣的轉換流InputStreamReader()方法,可以将位元組流轉換成字元流
 * @author wl-pc
*/
public class TransStreamDemo {
	public static void main(String[] args) {
		//為了提高效率,将字元串進行緩沖區技術高效操作,使用BufferedReader類中的方法
		BufferedReader bufr=null;
		try {
			//1.擷取鍵盤錄入對象
			//InputStream in = System.in;
			//2.将位元組流對象轉換成字元流對象,使用轉換流InputStreamReader()方法
			//InputStreamReader isr = new InputStreamReader(in);  //得到字元流in
			//bufr = new BufferedReader(isr);
			
			//鍵盤錄入最常見寫法:以上三句話變為一句話(如下:)
			bufr = new BufferedReader(new InputStreamReader(System.in));
				
			//2.将字元流對象轉換成位元組流對象,使用轉換流OutputStreamWriter()方法
			//OutputStream out = System.out;   //得到輸出流
			//OutputStreamWriter osw = new OutputStreamWriter(out);
			//裝飾類,用來裝飾轉化流OutputStreamWriter類的。
			//可以調用bufferedWriter中的newLine()方法,誇平台換行
			//BufferedWriter bufw = new BufferedWriter(osw);   
			
			//以上三句話變為一句話(如下:)
			BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));
			
			String line = null;
			while((line=bufr.readLine())!=null){
				if("over".equals(line))
					break;
				bufw.write(line.toUpperCase());
				bufw.newLine();
				bufw.flush();
			}
		} catch (IOException e) {
			System.out.println(e.toString());
		} finally{
			if(bufr!=null){
				try {
					bufr.close();
				} catch (IOException e) {
					System.out.println("close:"+e.toString());
				}
			}
		}
	}
}
           
例子14:關于流操作的基本規律,示範例子      
package cn.itheima.day03;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
/**
 * 1.
 *   源:鍵盤錄入
 *   目的:控制台
 * @author wl-pc
 * 2.改變需求:想把鍵盤錄入的資料存儲到一個檔案中
 *   源:鍵盤
 *   目的:檔案
 *   
 * 3.改變需求:想要将一個檔案資料列印到控制上
 *   源:檔案
 *   目的:控制台
 *   
 *   ######################流操作的基本規律:##########################
 *     最痛苦的就是流對象有很多,不知道該用哪一個?                                    
 *      通過三個明确來完成:                                                            
 *        1.明确源和目的                                                           
 *           源:輸入流.    InputStream    Reader                                                  
 *         目的:輸出流.   OutputStream    Writer                                                      
 *        2.明确操作的資料是否是存文本   
 *           是純文字:用字元流
 *         不是純文字:用位元組流    
 *        3.當體系明确後,再明确要使用哪個具體的對象
 *           通過裝置來進行區分:
 *              源裝置:記憶體、硬碟、鍵盤
 *            目的裝置:記憶體、硬碟(檔案)、控制台            
 *   ----------------------3個需求之一----------------------------------      
 *     1.将一個文本檔案中的資料存儲到另一個檔案中  ,也就是複制檔案
 *          源:因為是源,是以使用讀取流:InputStream     Reader
 *              a.是不是操作文本檔案?
 *                   是:這就可以選擇Reader
 *                 不是:可以選擇InputStream
 *             這樣下來,所屬體系就明确了。
 *             
 *             b.接下來就要明确要使用體系中的哪個對象?
 *               明确裝置:硬碟上的一個檔案
 *               Reader體系中可以操作檔案的對象是FileReader
 *             c.是否需要提高效率?
 *                需要:加入Reader體系的緩沖區:BufferedReader
 *               
 *       接下來就是: 1) FileReader fr = new FileReader("a.txt");        
 *                    2) BufferedReader br = new BufferedReader(fr);
 *             
 *             
 *          目的:檔案 OutputStream    Writer
 *             a.目的是否是純文字的?
 *                是:Writer
 *              不是:OutputStream 
 *             b.明确裝置:硬碟上的一個檔案
 *                Writer體系中可以操作一個檔案的對象是FileWriter
 *                
 *             c.是否需要提高效率?
 *                 需要:加入Writer體系的緩沖區:BufferedWriter
 *             
 *       接下來就是: 1) FileWriter fw = new FileWriter("b.txt");
 *                    2) BufferedWriter bw = new BufferedWriter(fw); 
 *                 
 *     練習: 将一個圖檔檔案中的資料存儲到另一個圖檔中 ,即為copy圖檔,要按照以上的格式去寫                                       
 *          源(是圖檔):因為是源, 是以使用讀取流:InputStream    Reader
 *                a.是不是操作的純文字檔案?
 *                 不是:這就可以選擇InputStream
 *                   是:這就可以選擇 Reader   
 *                b.接下來就要明确要使用體系中的哪個對象?   
 *                   明确裝置:硬碟上的一個圖檔
 *                   InputStream體系中可以操作圖檔的對象時FileInputStream
 *                c.是否需要提高效率?
 *                   需要:加入InputStream體系的緩沖區:BufferedInputStream
 *        
 *         接下來就是:FileInputStream fis = new FileInputStream("1.jpg");
 *                     BufferedInputStream bis = new BufferedInputStream(fis);
 *                    
 *           目的:檔案  OutputStream      Writer
 *                 a.是否是純文字的檔案?
 *                    不是:OutputStream 
 *                      是:writer
 *                 b.明确裝置:硬碟上的一個圖檔
 *                     OutputStream體系中可以操作一個檔案的對象是FileOutputStream
 *                 c.是否需要提高效率?
 *                 需要:加入OutputStream體系的緩沖區:BufferedOutputStream    
 *                                                
 *         接下來就是: FileOutputStream fos = new FileOutputStream("2.jpg");
 *                      BufferedOutputStream bos = new BufferedOutputStream(fos);                                        
 *                                                                 
 *   #################################################################
 */
public class TransStreamDemo2 {
	public static void main(String[] args) {
		//為了提高效率,将字元串進行緩沖區技術高效操作,使用BufferedReader類中的方法
		BufferedReader bufr=null;
		try {
			/*需求2的實作
			 * bufr = new BufferedReader(new InputStreamReader(System.in));
			BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("F:\\Javajichu\\JavaLianXi\\src\\cn\\itheima\\day03\\out.txt")));
*/
			//需求3的實作
			bufr=new BufferedReader(new InputStreamReader(new FileInputStream("F:\\Javajichu\\JavaLianXi\\src\\cn\\itheima\\day03\\CopyPic.java")));
			BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));
			String line = null;
			while((line=bufr.readLine())!=null){
				if("over".equals(line))
					break;
				bufw.write(line.toUpperCase());
				bufw.newLine();
				bufw.flush();
			}
		} catch (IOException e) {
			System.out.println(e.toString());
		} finally{
			if(bufr!=null){
				try {
					bufr.close();
				} catch (IOException e) {
					System.out.println("close:"+e.toString());
				}
			}
		}
	}
}
           
例子15:将系統出現的異常資訊存儲到檔案中      
package cn.itheima.day03;
import java.io.FileNotFoundException;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
 * 将系統出現的異常資訊存儲到檔案中
 * @author wl-pc
 */
public class ExceptionInfo {
	public static void main(String[] args) {
		try {
			int [] arr = new int[2];
			System.out.println(arr[3]);
		} catch (Exception e) {
			try {
				PrintStream ps= new PrintStream("F:\\Javajichu\\JavaLianXi\\src\\cn\\itheima\\day03\\exceptioninfo.txt"); 
				Date d = new Date();
				SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
				String s = sdf.format(d); 
				ps.println(s.toString());
				e.printStackTrace(ps);
			} catch (FileNotFoundException e1) {
				e1.printStackTrace();
			}
		}
	}
}
           
例子16:列印系統資訊到硬碟上的一個檔案中      
package cn.itheima.day03;
import java.io.FileNotFoundException;
import java.io.PrintStream;
import java.util.Properties;
public class SystemInfo {
	public static void main(String[] args) {
		Properties properties = System.getProperties();
		//System.out.println(properties);
        //properties.list(System.out);
        try {
			properties.list(new PrintStream("F:\\Javajichu\\JavaLianXi\\src\\cn\\itheima\\day03\\sysinfo.txt"));
		} catch (FileNotFoundException e) {
			System.out.println(e.toString());
		}
	}
}