黑馬程序員 java基礎--IO流(1)

                                                                     -------android培訓java培訓java學習型技術博客、期待與您交流! ----------

概述:

1、IO流:即Input Output的縮寫。

2、特點:

1)IO流用來處理設備間的數據傳輸。

2)Java對數據的操作是通過流的方式。

3)Java用於操作流的對象都在IO包中。

4)流按操作數據分爲兩種:字節流和字符流。

5)流按流向分爲:輸入流和輸出流。

注意:流只能操作數據,而不能操作文件。

3、IO流的常用基類:

1)字節流的抽象基流:InputStream和OutputStream

2)字符流的抽象基流:Reader和Writer

注:此四個類派生出來的子類名稱都是以父類名作爲子類名的後綴,以前綴爲其功能;如InputStream子類FileInputStream和Reader子類FileReader

用兩張圖來說明Java中IO流操作有關的類和IO流類圖結構



                                                                                            

                                                  知識點一   字符流

一、簡述:

1、字符流中的對象融合了編碼表。使用的是默認的編碼,即當前系統的編碼。

2、字符流Writer,Reader只是用於處理文字數據,而字節流InputStream,OutputStream可以處理媒體數據,像圖片,音頻和視頻等。

3、既然IO流是用於操作數據的,那麼數據的最常見體現形式是文件。專門用於操作文件的Writer子類對象:FileWriter   --->  後綴名爲父類名,前綴名爲流對象的功能。

二、字符流的讀寫

1、寫入字符流:

1)創建一個FileWriter對象,該對象一被初始化,就必須要明確被操作的文件。且該目錄下如果已有同名文件,則同名文件將被覆蓋。其實該步就是在明確數據要存放的目的地。

2)調用write(String s)方法,將字符串寫入到流中。

3)調用flush()方法,刷新該流的緩衝,將數據刷新到目的地中。

4)調用close()方法,是關閉流資源。但是關閉前會刷新一次內部的緩衝數據,並將數據刷新到目的地中。

特別要注意幾點:

①close()和flush()區別:flush()刷新後,流可以繼續使用;而close()刷新後,將會關閉流,不可再寫入字符流。

②其實java自身不能寫入數據,而是調用系統內部方式完成數據的書寫,使用系統資源後,一定要關閉資源。

③數據的續寫是通過構造函數 FileWriter(String s,boolean append),根據給定文件名及指示是否附加寫入數據的boolean值來構造FileWriter對象。

2、讀取字符流:

1)創建一個文件讀取流對象,和指定名稱的文件相關聯。要保證該文件已經存在,若不存在,將會發生異常FileNotFoundException。

2)調用讀取流對象的read()方法。read():一次讀一個字符,且會繼續往下讀。

      第一種方式:讀取單個字符。第二種方式:通過字符數組進行讀取。

3)讀取後要將流資源關閉。

舉例說明一下:

/*
那麼先以操作文件爲主來演示

需求:在硬盤上,創建一個文件,並寫入文字數據。

找到一個專門用於操作文件的Writer子類對象。FileWriter  後綴名是父類名,前綴名是該流對象的功能
*/
import java.io.*;
class FileWriteDemo
{
   public static void main(String []args) throws IOException
   {
     //創建一個FileWriter對象,該對象一被初始化就必須要明確被操作的文件
	 //而且該文件會被創建到指定的目錄下。如果該目錄下已有同名文件,將被覆蓋
	 //其實該步就是在明確數據要存放的目的地。
	 FileWriter fw =new FileWriter("C:/demo.txt");
	
	 fw.write("abcde");
	 //刷新流對象中緩衝中的數據
	 //將數據刷到目的地中
	 fw.flush();
	 
	  fw.write("分工哈哈哈哈");
	 //將數據刷到目的地中
	 fw.flush();
	
	 //關閉流資源,但是關閉之前會刷新一次緩衝中的數據
	 //講數據刷到目的地中,flush刷新後,流可以繼續使用,close刷新後,會將流關閉。
	 fw.close();
   }
   
}

三、IO異常的處理方式:

IO異常的處理方式
凡是與設備上的數據發生關係的,進行處理的都會發生IO異常,無論讀還是寫

異常是針對方法來說的,拋出、聲明拋出、捕獲和處理異常都是在方法中進行的。        Java異常處理通過5個關鍵字try、catch、throw、throws、finally進行管理。基本過程是用try語句塊包住要監視的語句,如果在try語句塊內出現異常,則異常會被拋出,你的代碼在catch語句塊中可以捕獲到這個異常並做處理;還有以部分系統生成的異常在Java運行時自動拋出。你也可以通過throws關鍵字在方法上聲明該方法要拋出異常,然後在方法內部通過throw拋出異常對象。異常中要記得在finally中判斷流對象是否爲空,並在使用完後關閉所有的流對象。

舉例說明:

import java.io.*;

class FileWriteDemo2
{
   public static void main(String []args)
   {
   //在外面建立引用,在try內初始化
   FileWriter fw=null;
   try{
   
       //try裏面定義的變量在外面訪問不到
       //FileWriter fw=new FileWriter("demo.txt");
	   
	   //向磁盤中寫入文件
	   fw=new FileWriter("c:\\demo.txt");
	   //向文件中寫入內容
	   fw.write("abcdefg");
	
	
   }catch(IOException e)
   {
     System.out.println("catch:"+e.toString());
	 //finally內關閉資源,一定會被執行的代碼往裏面放入
   }finally{
   
         try{
		 // 對流對象進行判斷,如果不爲空就關閉
		  if(fw!=null)
		  {
		     fw.close();
		  }
		       
			   
		  }catch(IOException e)
		  {
		     System.out.println(e.toString());
		  }
        
   }
    
   }   
}
四:文件的續寫

  /*
演示對已有文件的數據續寫。
*/
import java.io.*;

class FileWriteDemo3
{
   public static void main(String []args)
   {
   //在外面建立引用,在try內初始化
   FileWriter fw=null;
   try{
   
       //try裏面定義的變量在外面訪問不到
       //FileWriter fw=new FileWriter("demo.txt");
	   
	   //向磁盤中寫入文件
	   //傳遞一個true參數,代表不覆蓋已有的文件,並在已有文件的末尾處進行數據的續寫
	   fw=new FileWriter("c:\\demo.txt",true);
	   //向文件中寫入內容
	   fw.write("nihao\r\nxiexie");
	
	
   }catch(IOException e)
   {
     System.out.println("catch:"+e.toString());
	 //finally內關閉資源,一定會被執行的代碼往裏面放入
   }finally{
   
         try{
		 // 對流對象進行判斷,如果不爲空就關閉
		  if(fw!=null)
		  {
		     fw.close();
		  }
		       
			   
		  }catch(IOException e)
		  {
		     System.out.println(e.toString());
		  }
        
   }
    
   }   
}

五、文本文件讀取方式


/*第一種方式:一次讀取一個字符*/import java.io.*;

class FileReaderDemo
{
   public static void main(String []args) throws IOException
   { 
       //創建一個文件讀流對象,和指定名稱的文件相關聯
       //要保證該文件時已經存在的,如果不存在,會發生異常FileNotFoundException
       FileReader fr=new FileReader("C:/demo.txt");
	   //調用讀取流對象的read方法
	   //raed()方法一次讀入一個字符,而且會自動往下讀。
	   /*
	   int ch=fr.read();
	   
	   System.out.println("ch="+(char)ch);
	   
	   int ch1=fr.read();
	   
	   System.out.println("ch="+(char)ch1);
	   
	   */
	   //read方法作爲整數讀取的字符,範圍在0到65535之間,如果達到流的末尾,則返回-1
	   
	   /*
	   while(true)
	   {
	      int ch=fr.read();
		  if(ch==-1)
		     break;
		  System.out.println("ch="+(char)ch);
	   }
	   fr.close();
	   */
	   int ch=0;
	   
	   while((ch=fr.read())!=-1)
	   {
	     System.out.println("ch="+(char)ch); 
	   }
   }
}

/*
第二種方式,通過字符數組進行讀取。

這種讀取方式最有效
*/

import java.io.*;

class FileReaderDemo2
{
   public static void main(String []args) throws IOException
   { 
     FileReader fr=new FileReader("C:/demo.txt");
	 
	 //定義一個字符數組。用於存儲讀到字符
	 //該read(char[])返回的是讀到的字符個數
	 
	 char [] buf=new char[1024];
	 /*
	 int num=fr.read(buf);
	 
	 System.out.println("num="+num+"..."+new String(buf));
	 
	 int num1=fr.read(buf);
	 
	 System.out.println("num1="+num1+"..."+new String(buf));
	 
	 int num2=fr.read(buf);
	 
	 System.out.println("num2="+num2+"..."+new String(buf,0,1));
    	*/ 
	int num=0;
	while((num=fr.read(buf))!=-1)
	{
	  System.out.println(new String(buf,0,num));
	}
	fr.close(); 
   }
}

六、拷貝文本文件:

將C盤一個文本文件複製到D盤。
複製的原理:
其實就是將C盤下的文件數據存儲到D盤的一個文件中。
步驟:
1,在D盤創建一個文件。用於存儲C盤文件中的數據。
2,定義讀取流和C盤文件關聯。
3,通過不斷的讀寫完成數據存儲。

方式一:讀取一個字符,存入一個字符
方式二:先將讀取的數據存入到內存中,再將存入的字符取出寫入D盤
4,關閉資源:輸入流資源和輸出流資源。
舉例:

import java.io.*;

class CopyText 
{
	public static void main(String[] args) throws IOException
	{
		copy_2();
	}


	public static void copy_2()
	{
		FileWriter fw = null;
		FileReader fr = null;
		try
		{
			fw = new FileWriter("SystemDemo_copy.txt");
			fr = new FileReader("SystemDemo.java");

			char[] buf = new char[1024];

			int len = 0;
			while((len=fr.read(buf))!=-1)
			{
				fw.write(buf,0,len);
			}
		}
		catch (IOException e)
		{
			throw new RuntimeException("讀寫失敗");

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

	//從C盤讀一個字符,就往D盤寫一個字符。
	public static void copy_1()throws IOException
	{
		//創建目的地。
		FileWriter fw = new FileWriter("RuntimeDemo_copy.txt");

		//與已有文件關聯。
		FileReader fr = new FileReader("RuntimeDemo.java");

		int ch = 0;

		while((ch=fr.read())!=-1)
		{
			fw.write(ch);
		}
		
		fw.close();
		fr.close();

	}
}

示意圖:


七、BufferedWriter和BufferedReader:字符流緩衝區

1、緩衝區的出現:提高了流的讀寫效率,所以在緩衝區創建前,要先創建流對象,即先將流對象初始化到構造函數中。

2、緩衝技術原理:此對象中封裝了數組,將數據存入,在一次性取出。

3、寫入流緩衝區BufferedWriter的步驟:

1)創建一個字符寫入流對象

2)爲提高字符寫入流效率,加入緩衝技術,只要將需要被提高效率的流對象作爲參數傳遞給緩衝區的構造函數即可。

      注意,只要用到緩衝去就需要刷新。

3)其實關閉緩衝區就是在關閉緩衝區中的流對象。

      該緩衝區中提供了一個跨平臺的換行符:newLine()。

4、讀取流緩衝區BufferedReader的步驟:

1)創建一個讀取流對象和文件關聯

2)爲提高效率,加入緩衝技術,將字符讀取流對象作爲參數傳遞給緩衝對象的構造函數。

3)該緩衝區提供了一個一次讀一行的方法readLine(),方便與對文本數據的獲取,當返回null時,表示讀到文件末尾。

      readLine()方法返回的時只返回回車符之前的數據內容,並不返回回車符,即讀取的內容中不包含任何行終止符(回車符和換行符)。

--->readLine()方法原理:無論是讀一行,或讀取多個字符,其實最終都是在硬盤上一個一個讀取。所以最終使用的還是read方法一次讀一個。

5、使用緩衝技術拷貝文件,提高效率:

/*
緩衝區的出現是爲了提高流的操作效率而出現的

所以在創建緩衝區之前,必須要先有流對象

\r\n是在windows下換行 \n在linux是換行

該緩衝區中提供了一個跨平臺的換行符
newLine();
*/
import java.io.*;

class BufferedWriterDemo
{
   public static void main(String []args) throws IOException
   { 
     //創建一個字符寫入流流對象
	 FileWriter fw=new FileWriter("buf.txt");
	 
	 //爲了提高字符寫入流的效率,加入緩衝技術(原理就是這個對象裏面封裝了數組)
	 //只要將需要被提高效率的流對象作爲參數傳遞給緩衝區的構造函數即可
	 BufferedWriter  bufw=new BufferedWriter(fw);
	
	for(int x=1;x<5;x++)
	{
	   bufw.write("abcd"+x);
	    bufw.newLine();
		bufw.flush();
	}
     //bufw.write("abcde");
     //bufw .write("\r\n");
	 //newLine()在任何系統平臺下都是換行
	// bufw.newLine();
	 
	 //記住,只要用到緩衝區,就要記得刷新
	 //bufw.flush();
	 
	 //其實關閉緩衝區,就是在關閉緩衝區中的流對象
	 bufw.close();
	 
   }
}

/*
字符讀取流緩衝區:

該緩衝區提供了一個一次讀一行的方法readLine,方便於對文本數據的獲取。
當返回null時,表示讀到文件末尾。
*/
import java.io.*;
class BufferedReaderDemo
{
   public static void main(String []args) throws IOException
   { 
     //創建一個讀取流對象和文件相關聯
	 FileReader fr=new FileReader("buf.txt");
	 //爲了提高效率,加入緩衝技術。將字符讀取流對象作爲參數傳遞給緩衝對象的構造函數
	 BufferedReader bufr=new BufferedReader(fr);
	 
	 String line=null;
	 while((line=bufr.readLine())!=null)
	 {
	    System.out.println(line);
	 }
	 /*
	String s1=bufr.readLine();
	 
	System.out.println("s1:"+s1);
	
	String s2=bufr.readLine();
	 
	System.out.println("s2:"+s2);
	*/
	bufr.close();
   }
   
}

示意圖:



八、MyBufferedReader(自定義BufferedReader):

原理:可根據BufferedReader類中特有發那個發readLine()的原理,自定義一個類中包含相同功能的方法

步驟:1.初始化自定義的類,加入流對象。

            2.定義一個臨時容器,原BufferedReader封裝的是字符數組,此類中可定義一個StringBuilder的容器,最終可實現字符串的提取。

/*
明白了BufferedReader類中特有方法readLine的原理後,
可以自定義一個類中包含一個功能和readline一致的方法
來模擬一下BufferedReader
*/
import java.io.*;

class MyBufferedReader extends Reader
{
  
  //裝飾設計模式
   private Reader r=null;
   
   MyBufferedReader(Reader r)
   {
      this.r=r;
   }
   //可以一次讀一行數據的方法
   public String myReadLine() throws IOException
   {
     //定義一個臨時容器,員BufferedReader封裝的是字符數組
	 //爲了演示方便,定義一個StringBulilder容器,因爲最終還是要將數據變成字符串。
	 StringBuilder sb=new StringBuilder();
	 int ch=0;
	 while((ch=r.read())!=-1)
	 {
	   if(ch=='\r')
	   continue;
	   if(ch=='\n')
		return sb.toString();
	   else
	   sb.append((char)ch);
	 }
	 //如果沒有遇到\n,sb中而且有數據的話也要返回
	  if(sb.length()!=0)
        return sb.toString();
	 return null;
   }
  /*
  覆蓋類中的抽象方法
  */
  public int read(char[] cbuf,int off,int len)throws IOException
  {
    return r.read(cbuf,off,len);
  }
  
  public void close() throws IOException
  {
      r.close();
  }
  
  public void myClose() throws IOException
  {
      r.close(); 
  }
}



class MyBufferedReaderDemo
{
   public static void main(String[] args) throws IOException
   {
      FileReader fr=new FileReader("buf.txt");
	  
	  MyBufferedReader myBuf=new MyBufferedReader(fr);
   
      String line=null;
	  
	  while((line=myBuf.myReadLine())!=null)
	  {
	    System.out.println(line);
	  }
	  
      myBuf.myClose();
   }
   
}

九、裝飾設計模式:

1、簡述:當想對已有對象進行功能增強是,可定義類:將已有對象傳入,基於已有對象的功能,並提供加強功能,那麼自定義的該類稱之爲裝飾類。即對原有類進行了優化。

裝飾設計模式:
當想要對已有的對象進行功能增強時,
可以定義一個類,將已有對象傳入,基於已有的功能,並提供加強功能
那麼自定義的該類稱爲裝飾類
裝飾類通常會通過構造方法接受被裝飾的對象
並基於被裝飾的對象的功能,提供更詳細的功能。

2、特點:裝飾類通常都會通過構造方法接收被裝飾的對象,並基於被裝飾的對i型那個的功能提供更強的功能。

3、裝飾和繼承的區別:

1)裝飾模式比繼承要靈活,通過避免了繼承體系的臃腫,且降低了類與類間的關係。

2)裝飾類因爲增強已有對象,具備的功能和已有的是相同的,只不過提供了更強的功能,所以裝飾類和被裝飾的類通常都是屬於一個體系。

3)從繼承結構轉爲組合結構。

注:在定義類的時候,不要以繼承爲主;可通過裝飾設計模式進行增強類功能。靈活性較強,當裝飾類中的功能不適合,可再使用被裝飾類的功能。

        要繼承相應的父類,就需要將所有的抽象方法實現,或交給子類實現。其中MyBufferedReader的例子就是最好的裝飾設計模式的例子,就是                 對BufferedReader的增強。

舉例:

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("吸根菸");
  }
  
}
class PersonDemo
{
   public static void main(String[] args)
   {
       Person p=new Person();
	 //	 p.chifan();
	 SuperPerson sp=new SuperPerson(p);
	 
	 sp.superChifan();
   }
   
}

/*
明白了BufferedReader類中特有方法readLine的原理後,
可以自定義一個類中包含一個功能和readline一致的方法
來模擬一下BufferedReader
*/
import java.io.*;

class MyBufferedReader extends Reader
{
  
  //裝飾設計模式
   private Reader r=null;
   
   MyBufferedReader(Reader r)
   {
      this.r=r;
   }
   //可以一次讀一行數據的方法
   public String myReadLine() throws IOException
   {
     //定義一個臨時容器,員BufferedReader封裝的是字符數組
	 //爲了演示方便,定義一個StringBulilder容器,因爲最終還是要將數據變成字符串。
	 StringBuilder sb=new StringBuilder();
	 int ch=0;
	 while((ch=r.read())!=-1)
	 {
	   if(ch=='\r')
	   continue;
	   if(ch=='\n')
		return sb.toString();
	   else
	   sb.append((char)ch);
	 }
	 //如果沒有遇到\n,sb中而且有數據的話也要返回
	  if(sb.length()!=0)
        return sb.toString();
	 return null;
   }
  /*
  覆蓋類中的抽象方法
  */
  public int read(char[] cbuf,int off,int len)throws IOException
  {
    return r.read(cbuf,off,len);
  }
  
  public void close() throws IOException
  {
      r.close();
  }
  
  public void myClose() throws IOException
  {
      r.close(); 
  }
}



class MyBufferedReaderDemo
{
   public static void main(String[] args) throws IOException
   {
      FileReader fr=new FileReader("buf.txt");
	  
	  MyBufferedReader myBuf=new MyBufferedReader(fr);
   
      String line=null;
	  
	  while((line=myBuf.myReadLine())!=null)
	  {
	    System.out.println(line);
	  }
	  
      myBuf.myClose();
   }
   
}
十、LineNumberReader和MyLineNumberReader
在BufferedReader中有個直接的子類LineNumberReader,其中有特有的方法獲取和設置行號:

setLineNumber()和getLineNumber()

原理:LineNumberReader中有一個計數器,定義一個Reader流對象,當讀到流對象的時候才能進行行號的添加

示例:

import java.io.*;

class LineNumberReaderDemo
{
   public static void main(String[] args) throws IOException
   { 
      FileReader fr=new FileReader("PersonDemo.java");
	  
	  LineNumberReader lnr=new LineNumberReader(fr);
	  
	  String line=null;

	  lnr.setLineNumber(100);
	  
	  while((line=lnr.readLine())!=null)
	  {
	     System.out.println(lnr.getLineNumber()+":"+line);
	  }
	 
	  lnr.close();
   }
   
}

/*

*/
import java.io.*;

class MyLineNumberReader  extends MyBufferedReader
{  
   private Reader r;
   private int lineNumber;
   MyLineNumberReader(Reader r)
   {
      super(r);
   }
   public String myReadLine() throws IOException
   {
   
     lineNumber++; 
     return super.myReadLine();
   }
   
   public void setLineNumber(int lineNumber)
   { 
      this.lineNumber=lineNumber;
   }
   public int getLineNumber()
   {
      return lineNumber;
   }
}

/*
class MyLineNumberReader 
{
   private Reader r;
   private int lineNumber;
   MyLineNumberReader(Reader r)
   {
      this.r=r;
   }
   public String myReadLine() throws IOException
   {
   
     lineNumber++; 
     StringBuilder sb=new StringBuilder();
	 int ch=0;
	 
	 while((ch=r.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 setLineNumber(int lineNumber)
   { 
      this.lineNumber=lineNumber;
   }
   public int getLineNumber()
   {
      return lineNumber;
   }
   
   public void myClose()throws IOException
   {
     r.close();
   }
   
}
*/
class MyLineNumberReaderDemo
{
   public static void main(String[] number) throws IOException
   {
       FileReader fr=new FileReader("copyTextByBuf.java");
	   
	   MyLineNumberReader mylnr=new MyLineNumberReader(fr);
	   
	   String line=null;
	   mylnr.setLineNumber(100);
	   while((line=mylnr.myReadLine())!=null)
	   {
	     System.out.println(mylnr.getLineNumber()+"::"+line);
	   }
	    mylnr.myClose();
   }  
}

最新最全的的java學習視頻教程:http://pro.net.itcast.cn/View-22-1458.aspx

                                          -------android培訓java培訓java學習型技術博客、期待與您交流! ----------

詳細請查看:http://edu.csdn.net/heima






發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章