java IO流

 

1.掌握流的概念

2.掌握字節流與字符流的作用

3.掌握文件的標準操作步驟

4.掌握字節與字符操作的區別

1、流的概念


程序中的輸入輸出都是以流的形式保存的,流中保存的實際上全都是字節文件。

2、字節流與字符流


內容操作就四個類:OutputStream、InputStream、writer、Rader

使用 File 類操作的時候一定要有路徑的問題,注意分隔符

實際上四個操作類都是抽象類

IO操作屬於資源操作,對於資源操作,操作的最後必須關閉,否則就有可能出現未知錯誤。

3.字節流


Byte 是字節,肯定使用字節流操作。所有的數基本都可以直接使用 byte 數組表示出來。

字節輸出流: OutputStream 類


Clonseable: 表示可以關閉的操作,因爲程序運行到最後肯定要關閉。

Fluashable: 表示刷新,清空內在中的數據。

  1. import java.io.File ;  
  2. import java.io.OutputStream ;  
  3. import java.io.FileOutputStream ;  
  4. public class OutputStreamDemo01{  
  5.     public static void main(String args[]) throws Exception{    // 異常拋出,不處理   
  6.         // 第1步、使用File類找到一個文件   
  7.         File f= new File("d:" + File.separator + "test.txt") ;  // 聲明File對象   
  8.         // 第2步、通過子類實例化父類對象   
  9.         OutputStream out = null ;   // 準備好一個輸出的對象   
  10.         out = new FileOutputStream(f)  ;    // 通過對象多態性,進行實例化   
  11.         // 第3步、進行寫操作   
  12.         String str = "Hello World!!!" ;     // 準備一個字符串   
  13.         byte b[] = str.getBytes() ;         // 只能輸出byte數組,所以將字符串變爲byte數組   
  14.         out.write(b) ;                      // 將內容輸出,保存文件   
  15.         // 第4步、關閉輸出流   
  16.         out.close() ;                       // 關閉輸出流   
  17.     }  
  18. };  

在操作的時候,如果文件本身不存在,則會爲用戶自動創建新文件。

在操作輸出流的時候,也可以使用 write(int i) 的方法寫出數據

  1. import java.io.File ;  
  2. import java.io.OutputStream ;  
  3. import java.io.FileOutputStream ;  
  4. public class OutputStreamDemo02{  
  5.     public static void main(String args[]) throws Exception{    // 異常拋出,不處理   
  6.         // 第1步、使用File類找到一個文件   
  7.         File f= new File("d:" + File.separator + "test.txt") ;  // 聲明File對象   
  8.         // 第2步、通過子類實例化父類對象   
  9.         OutputStream out = null ;   // 準備好一個輸出的對象   
  10.         out = new FileOutputStream(f)  ;    // 通過對象多態性,進行實例化   
  11.         // 第3步、進行寫操作   
  12.         String str = "Hello World!!!" ;     // 準備一個字符串   
  13.         byte b[] = str.getBytes() ;         // 只能輸出byte數組,所以將字符串變爲byte數組   
  14.         for(int i=0;i<b.length;i++){     // 採用循環方式寫入   
  15.             out.write(b[i]) ;   // 每次只寫入一個內容   
  16.         }  
  17.         // 第4步、關閉輸出流   
  18.         out.close() ;                       // 關閉輸出流   
  19.     }  
  20. };  

以上的操作中在寫入數據之後,文件之前的內容已經不存在了,因爲在IO操作中默認的情況是將其進行覆蓋的,那麼如果現在要想執行追加的功能,則必須設置追加的操作,找到FileOutputStream 類;


  1. import java.io.File ;  
  2. import java.io.OutputStream ;  
  3. import java.io.FileOutputStream ;  
  4. public class OutputStreamDemo03{  
  5.     public static void main(String args[]) throws Exception{    // 異常拋出,不處理   
  6.         // 第1步、使用File類找到一個文件   
  7.         File f= new File("d:" + File.separator + "test.txt") ;  // 聲明File對象   
  8.         // 第2步、通過子類實例化父類對象   
  9.         OutputStream out = null ;   // 準備好一個輸出的對象   
  10.         out = new FileOutputStream(f,true)  ;   // 此處表示在文件末尾追加內容   
  11.         // 第3步、進行寫操作   
  12.         String str = "Hello World!!!" ;     // 準備一個字符串   
  13.         byte b[] = str.getBytes() ;         // 只能輸出byte數組,所以將字符串變爲byte數組   
  14.         for(int i=0;i<b.length;i++){     // 採用循環方式寫入   
  15.             out.write(b[i]) ;   // 每次只寫入一個內容   
  16.         }  
  17.         // 第4步、關閉輸出流   
  18.         out.close() ;                       // 關閉輸出流   
  19.     }  
  20. };  

程序本身是可以追加內容了,但是沒有換行,是直接在末尾追加的。

如果在文件操作中想換行的話,使用  “\r\n” 完成。

  1. import java.io.File ;  
  2. import java.io.OutputStream ;  
  3. import java.io.FileOutputStream ;  
  4. public class OutputStreamDemo04{  
  5.     public static void main(String args[]) throws Exception{    // 異常拋出,不處理   
  6.         // 第1步、使用File類找到一個文件   
  7.         File f= new File("d:" + File.separator + "test.txt") ;  // 聲明File對象   
  8.         // 第2步、通過子類實例化父類對象   
  9.         OutputStream out = null ;   // 準備好一個輸出的對象   
  10.         out = new FileOutputStream(f,true)  ;   // 此處表示在文件末尾追加內容   
  11.         // 第3步、進行寫操作   
  12.         String str = "\r\nHello World!!!" ;     // 準備一個字符串   
  13.         byte b[] = str.getBytes() ;         // 只能輸出byte數組,所以將字符串變爲byte數組   
  14.         for(int i=0;i<b.length;i++){     // 採用循環方式寫入   
  15.             out.write(b[i]) ;   // 每次只寫入一個內容   
  16.         }  
  17.         // 第4步、關閉輸出流   
  18.         out.close() ;                       // 關閉輸出流   
  19.     }  
  20. };  
字節輸入流:InputStream


  1. import java.io.File ;  
  2. import java.io.InputStream ;  
  3. import java.io.FileInputStream ;  
  4. public class InputStreamDemo01{  
  5.     public static void main(String args[]) throws Exception{    // 異常拋出,不處理   
  6.         // 第1步、使用File類找到一個文件   
  7.         File f= new File("d:" + File.separator + "test.txt") ;  // 聲明File對象   
  8.         // 第2步、通過子類實例化父類對象   
  9.         InputStream input = null ;  // 準備好一個輸入的對象   
  10.         input = new FileInputStream(f)  ;   // 通過對象多態性,進行實例化   
  11.         // 第3步、進行讀操作   
  12.         byte b[] = new byte[1024] ;     // 所有的內容都讀到此數組之中   
  13.         input.read(b) ;     // 讀取內容   
  14.         // 第4步、關閉輸出流   
  15.         input.close() ;                     // 關閉輸出流   
  16.         System.out.println("內容爲:" + new String(b)) ;    // 把byte數組變爲字符串輸出   
  17.     }  
  18. };  
此時,內容確實已經讀取進來了,但是可以發現存在問題。

  1. import java.io.File ;  
  2. import java.io.InputStream ;  
  3. import java.io.FileInputStream ;  
  4. public class InputStreamDemo02{  
  5.     public static void main(String args[]) throws Exception{    // 異常拋出,不處理   
  6.         // 第1步、使用File類找到一個文件   
  7.         File f= new File("d:" + File.separator + "test.txt") ;  // 聲明File對象   
  8.         // 第2步、通過子類實例化父類對象   
  9.         InputStream input = null ;  // 準備好一個輸入的對象   
  10.         input = new FileInputStream(f)  ;   // 通過對象多態性,進行實例化   
  11.         // 第3步、進行讀操作   
  12.         byte b[] = new byte[1024] ;     // 所有的內容都讀到此數組之中   
  13.         int len = input.read(b) ;       // 讀取內容   
  14.         // 第4步、關閉輸出流   
  15.         input.close() ;                     // 關閉輸出流\   
  16.         System.out.println("讀入數據的長度:" + len) ;  
  17.         System.out.println("內容爲:" + new String(b,0,len)) ;  // 把byte數組變爲字符串輸出   
  18.     }  
  19. };  
 這個代碼還存在問題,現在文件沒有這麼大,但是開闢了這麼大的數組空間,這樣肯定很浪費,能不能根據文件大小來開闢數組空間呢?

如果要想知道文件大小,直接使用File 類即可。

  1. import java.io.File ;  
  2. import java.io.InputStream ;  
  3. import java.io.FileInputStream ;  
  4. public class InputStreamDemo03{  
  5.     public static void main(String args[]) throws Exception{    // 異常拋出,不處理   
  6.         // 第1步、使用File類找到一個文件   
  7.         File f= new File("d:" + File.separator + "test.txt") ;  // 聲明File對象   
  8.         // 第2步、通過子類實例化父類對象   
  9.         InputStream input = null ;  // 準備好一個輸入的對象   
  10.         input = new FileInputStream(f)  ;   // 通過對象多態性,進行實例化   
  11.         // 第3步、進行讀操作   
  12.         byte b[] = new byte[(int)f.length()] ;      // 數組大小由文件決定   
  13.         int len = input.read(b) ;       // 讀取內容   
  14.         // 第4步、關閉輸出流   
  15.         input.close() ;                     // 關閉輸出流\   
  16.         System.out.println("讀入數據的長度:" + len) ;  
  17.         System.out.println("內容爲:" + new String(b)) ;    // 把byte數組變爲字符串輸出   
  18.     }  
  19. };  
以上直接使用 byte 數組的方式完成的。

現在使用 public abstract int read() throws IOException 讀取內容。

  1. import java.io.File ;  
  2. import java.io.InputStream ;  
  3. import java.io.FileInputStream ;  
  4. public class InputStreamDemo04{  
  5.     public static void main(String args[]) throws Exception{    // 異常拋出,不處理   
  6.         // 第1步、使用File類找到一個文件   
  7.         File f= new File("d:" + File.separator + "test.txt") ;  // 聲明File對象   
  8.         // 第2步、通過子類實例化父類對象   
  9.         InputStream input = null ;  // 準備好一個輸入的對象   
  10.         input = new FileInputStream(f)  ;   // 通過對象多態性,進行實例化   
  11.         // 第3步、進行讀操作   
  12.         byte b[] = new byte[(int)f.length()] ;      // 數組大小由文件決定   
  13.         for(int i=0;i<b.length;i++){  
  14.             b[i] = (byte)input.read() ;     // 讀取內容   
  15.         }  
  16.         // 第4步、關閉輸出流   
  17.         input.close() ;                     // 關閉輸出流\   
  18.         System.out.println("內容爲:" + new String(b)) ;    // 把byte數組變爲字符串輸出   
  19.     }  
  20. };  
以上的操作,只適合於知道輸入流大小的時候,如果現在不知道大小呢?
  1. import java.io.File ;  
  2. import java.io.InputStream ;  
  3. import java.io.FileInputStream ;  
  4. public class InputStreamDemo05{  
  5.     public static void main(String args[]) throws Exception{    // 異常拋出,不處理   
  6.         // 第1步、使用File類找到一個文件   
  7.         File f= new File("d:" + File.separator + "test.txt") ;  // 聲明File對象   
  8.         // 第2步、通過子類實例化父類對象   
  9.         InputStream input = null ;  // 準備好一個輸入的對象   
  10.         input = new FileInputStream(f)  ;   // 通過對象多態性,進行實例化   
  11.         // 第3步、進行讀操作   
  12.         byte b[] = new byte[1024] ;     // 數組大小由文件決定   
  13.         int len = 0 ;   
  14.         int temp = 0 ;          // 接收每一個讀取進來的數據   
  15.         while((temp=input.read())!=-1){  
  16.             // 表示還有內容,文件沒有讀完   
  17.             b[len] = (byte)temp ;  
  18.             len++ ;  
  19.         }  
  20.         // 第4步、關閉輸出流   
  21.         input.close() ;                     // 關閉輸出流\   
  22.         System.out.println("內容爲:" + new String(b,0,len)) ;  // 把byte數組變爲字符串輸出   
  23.     }  
  24. };  
當不知道讀取內容有多在的時候,就只能以讀取的數據是否爲-1爲讀完的標誌。
4.字符流

字符輸出流



字符流的操作比字節流操作好在一點, 就是可以直接輸出字符串了。不用再像之前那樣進行轉換操作了。

  1. import java.io.File ;  
  2. import java.io.Writer ;  
  3. import java.io.FileWriter ;  
  4. public class WriterDemo01{  
  5.     public static void main(String args[]) throws Exception{    // 異常拋出,不處理   
  6.         // 第1步、使用File類找到一個文件   
  7.         File f= new File("d:" + File.separator + "test.txt") ;  // 聲明File對象   
  8.         // 第2步、通過子類實例化父類對象   
  9.         Writer out = null ; // 準備好一個輸出的對象   
  10.         out = new FileWriter(f)  ;  // 通過對象多態性,進行實例化   
  11.         // 第3步、進行寫操作   
  12.         String str = "Hello World!!!" ;     // 準備一個字符串   
  13.         out.write(str) ;                        // 將內容輸出,保存文件   
  14.         // 第4步、關閉輸出流   
  15.         out.close() ;                       // 關閉輸出流   
  16.     }  
  17. };  

使用字符流默認請況下依然是覆蓋已有的文件,如果要想追加的話,則直接在FileWrite 上增加一個可追加的標記即可。

  1. import java.io.File ;  
  2. import java.io.Writer ;  
  3. import java.io.FileWriter ;  
  4. public class WriterDemo02{  
  5.     public static void main(String args[]) throws Exception{    // 異常拋出,不處理   
  6.         // 第1步、使用File類找到一個文件   
  7.         File f= new File("d:" + File.separator + "test.txt") ;  // 聲明File對象   
  8.         // 第2步、通過子類實例化父類對象   
  9.         Writer out = null ; // 準備好一個輸出的對象   
  10.         out = new FileWriter(f,true)  ; // 通過對象多態性,進行實例化   
  11.         // 第3步、進行寫操作   
  12.         String str = "\r\nLIXINGHUA\r\nHello World!!!" ;        // 準備一個字符串   
  13.         out.write(str) ;                        // 將內容輸出,保存文件   
  14.         // 第4步、關閉輸出流   
  15.         out.close() ;                       // 關閉輸出流   
  16.     }  
  17. };  
字符輸入流:Reader


以字符數組的形式讀取出數據。

  1. import java.io.File ;  
  2. import java.io.Reader ;  
  3. import java.io.FileReader ;  
  4. public class ReaderDemo01{  
  5.     public static void main(String args[]) throws Exception{    // 異常拋出,不處理   
  6.         // 第1步、使用File類找到一個文件   
  7.         File f= new File("d:" + File.separator + "test.txt") ;  // 聲明File對象   
  8.         // 第2步、通過子類實例化父類對象   
  9.         Reader input = null ;   // 準備好一個輸入的對象   
  10.         input = new FileReader(f)  ;    // 通過對象多態性,進行實例化   
  11.         // 第3步、進行讀操作   
  12.         char c[] = new char[1024] ;     // 所有的內容都讀到此數組之中   
  13.         int len = input.read(c) ;       // 讀取內容   
  14.         // 第4步、關閉輸出流   
  15.         input.close() ;                     // 關閉輸出流   
  16.         System.out.println("內容爲:" + new String(c,0,len)) ;  // 把字符數組變爲字符串輸出   
  17.     }  
  18. };  

也可以使用循環的方式,通過文件是否講到底的形式讀取。

  1. import java.io.File ;  
  2. import java.io.Reader ;  
  3. import java.io.FileReader ;  
  4. public class ReaderDemo02{  
  5.     public static void main(String args[]) throws Exception{    // 異常拋出,不處理   
  6.         // 第1步、使用File類找到一個文件   
  7.         File f= new File("d:" + File.separator + "test.txt") ;  // 聲明File對象   
  8.         // 第2步、通過子類實例化父類對象   
  9.         Reader input = null ;   // 準備好一個輸入的對象   
  10.         input = new FileReader(f)  ;    // 通過對象多態性,進行實例化   
  11.         // 第3步、進行讀操作   
  12.         char c[] = new char[1024] ;     // 所有的內容都讀到此數組之中   
  13.         int temp = 0 ;  // 接收每一個內容   
  14.         int len = 0 ;       // 讀取內容   
  15.         while((temp=input.read())!=-1){  
  16.             // 如果不是-1就表示還有內容,可以繼續讀取   
  17.             c[len] = (char)temp ;  
  18.             len++ ;  
  19.         }  
  20.         // 第4步、關閉輸出流   
  21.         input.close() ;                     // 關閉輸出流   
  22.         System.out.println("內容爲:" + new String(c,0,len)) ;  // 把字符數組變爲字符串輸出   
  23.     }  
  24. };  
5.字節流與字符流的區別

字節流和字符流使用是非常相似的,那麼除了操作代碼的不同之外,還有那些不同呢?

通過一個代碼來驗證字符流使用到了緩存。

  1. import java.io.File ;  
  2. import java.io.OutputStream ;  
  3. import java.io.FileOutputStream ;  
  4. public class OutputStreamDemo05{  
  5.     public static void main(String args[]) throws Exception{    // 異常拋出,不處理   
  6.         // 第1步、使用File類找到一個文件   
  7.         File f= new File("d:" + File.separator + "test.txt") ;  // 聲明File對象   
  8.         // 第2步、通過子類實例化父類對象   
  9.         OutputStream out = null ;   // 準備好一個輸出的對象   
  10.         out = new FileOutputStream(f)  ;    // 實例化   
  11.         // 第3步、進行寫操作   
  12.         String str = "Hello World!!!" ;     // 準備一個字符串   
  13.         byte b[] = str.getBytes() ;         // 只能輸出byte數組,所以將字符串變爲byte數組   
  14.         out.write(b) ;      // 寫入數據   
  15.         // 第4步、關閉輸出流   
  16.         // out.close() ;                        // 關閉輸出流   
  17.     }  
  18. };  
在使用字節流操作中,即使沒有關閉,最終也是可以輸出的。

  1. import java.io.File ;  
  2. import java.io.Writer ;  
  3. import java.io.FileWriter ;  
  4. public class WriterDemo03{  
  5.     public static void main(String args[]) throws Exception{    // 異常拋出,不處理   
  6.         // 第1步、使用File類找到一個文件   
  7.         File f= new File("d:" + File.separator + "test.txt") ;  // 聲明File對象   
  8.         // 第2步、通過子類實例化父類對象   
  9.         Writer out = null ; // 準備好一個輸出的對象   
  10.         out = new FileWriter(f)  ;  // 通過對象多態性,進行實例化   
  11.         // 第3步、進行寫操作   
  12.         String str = "Hello World!!!" ;     // 準備一個字符串   
  13.         out.write(str) ;                        // 將內容輸出,保存文件   
  14.         // 第4步、關閉輸出流   
  15.         // out.close() ;                        // 此時,沒有關閉   
  16.     }  
  17. };  

以上的操作,沒有輸出任何內容出來,也就是說,所有的內容現在都是保存在了緩衝區中,而如果執行關閉的時候會強制性的刷新緩衝區,所以可以把內容輸出。

如果現在假設,沒有關閉的話,也可以手式強制性調用刷新方法。

public abstract void flush()throws IOException

  1. import java.io.File ;  
  2. import java.io.Writer ;  
  3. import java.io.FileWriter ;  
  4. public class WriterDemo04{  
  5.     public static void main(String args[]) throws Exception{    // 異常拋出,不處理   
  6.         // 第1步、使用File類找到一個文件   
  7.         File f= new File("d:" + File.separator + "test.txt") ;  // 聲明File對象   
  8.         // 第2步、通過子類實例化父類對象   
  9.         Writer out = null ; // 準備好一個輸出的對象   
  10.         out = new FileWriter(f)  ;  // 通過對象多態性,進行實例化   
  11.         // 第3步、進行寫操作   
  12.         String str = "Hello World!!!" ;     // 準備一個字符串   
  13.         out.write(str) ;                        // 將內容輸出,保存文件   
  14.         // 第4步、關閉輸出流   
  15.         out.flush() ;   // 強制性清空緩衝區中的內容   
  16.         // out.close() ;                        // 此時,沒有關閉   
  17.     }  
  18. };  
問題:

開發中是使用字節流好還是字符流好。

在所有的硬盤上保存文件或是進行傳輸的時候都是以字節的方式進行的,包括圖片也是按字節完成,而字符是只有在內存中才會形成的,所以使用字節的操作是最多的。

6.操作範例


操作的時候要求可以按照如下的格式進行:

java Copy 源文件 目標文件

如果要採用以上的格式,則肯定要使用初始化參數的形式,輸入兩個路徑,所以此時就必須輸入參數的個數進行驗證,判斷其是否爲 2

是使用字符流還是使用字節流呢? 肯定使用字節流,因爲萬一拷貝的是一個圖片的。

要完成拷貝程序,兩種方式可以採用:

實現一:將源文件中的內容全部讀取進來,之後一次性寫入到目標文件

實現二:邊讀邊寫的方式

很明顯,使用第二種方式

  1. import java.io.* ;  
  2. public class Copy{  
  3.     public static void main(String args[]){  
  4.         if(args.length!=2){     // 判斷是否是兩個參數   
  5.             System.out.println("輸入的參數不正確。") ;  
  6.             System.out.println("例:java Copy 源文件路徑 目標文件路徑") ;  
  7.             System.exit(1) ;    // 系統退出   
  8.         }  
  9.         File f1 = new File(args[0]) ;   // 源文件的File對象   
  10.         File f2 = new File(args[1]) ;   // 目標文件的File對象   
  11.         if(!f1.exists()){  
  12.             System.out.println("源文件不存在!") ;  
  13.             System.exit(1) ;  
  14.         }  
  15.         InputStream input = null ;      // 準備好輸入流對象,讀取源文件   
  16.         OutputStream out = null ;       // 準備好輸出流對象,寫入目標文件   
  17.         try{  
  18.             input = new FileInputStream(f1) ;  
  19.         }catch(FileNotFoundException e){  
  20.             e.printStackTrace() ;  
  21.         }  
  22.         try{  
  23.             out = new FileOutputStream(f2) ;  
  24.         }catch(FileNotFoundException e){  
  25.             e.printStackTrace() ;  
  26.         }  
  27.         if(input!=null && out!=null){   // 判斷輸入或輸出是否準備好   
  28.             int temp = 0 ;    
  29.             try{  
  30.                 while((temp=input.read())!=-1){ // 開始拷貝   
  31.                     out.write(temp) ;   // 邊讀邊寫   
  32.                 }  
  33.                 System.out.println("拷貝完成!") ;  
  34.             }catch(IOException e){  
  35.                 e.printStackTrace() ;  
  36.                 System.out.println("拷貝失敗!") ;  
  37.             }  
  38.             try{  
  39.                 input.close() ;     // 關閉   
  40.                 out.close() ;       // 關閉   
  41.             }catch(IOException e){  
  42.                 e.printStackTrace() ;  
  43.             }  
  44.         }  
  45.     }     
  46. }  
總結:

1、掌握流的概念

2、掌握字節流和字符流操作文件的基本步驟

本章是以文件爲例,實際上以後的所有操作都可以通過此段代碼完成

3、字節流和字符流的區別

字節流:使用和到了緩衝區

4、邊讀、邊寫的方式在日後的開發中非常有用處。

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