Java I/O解讀與使用實例

轉載請註明出處http://blog.csdn.net/evankaka

           摘要:本文主要講解了Java I/O解讀與使用實例。

 一、I/O基本概念    

          I/O全稱是Input/Output,Java的I/O就是Java的輸入與輸出操作。與之相關的接口和類都放在java.io包裏面,因而,在進行Java輸入輸出操作時,需要導入該包。利用Java的I/O大大地擴展了系統的輸入與輸出範疇,不僅可以從控制檯輸入輸出,還可以從其他數據存儲形式進行輸入輸出,例如本地文件、遠程數據庫等。Java的I/O在文件數據的讀寫、數據的網絡發送與接收等很多場合發揮着重要作用。


       流是一組有順序的,有起點和終點的字節集合,是對數據傳輸的總稱或抽象。即數據在兩設備間的傳輸稱爲流,流的本質是數據傳輸,根據數據傳輸特性將流抽象爲各種類,方便更直觀的進行數據操作。對於文件內容的操作主要分爲兩大類分別是:字符流和字節流

(1)字節流有兩個抽象類:InputStream OutputStream其對應子類有FileInputStream和FileOutputStream實現文件讀寫。而BufferedInputStream和BufferedOutputStream提供緩衝區功能。



(2)字符流有兩個抽象類:Writer Reader其對應子類FileWriter和FileReader可實現文件的讀寫操作.BufferedWriter和BufferedReader能夠提供緩衝區功能,用以提高效率。



二、I/O流的分類

根據處理數據類型的不同分爲:字符流和字節流
根據數據流向不同分爲:輸入流和輸出流
字符流和字節流
字符流的由來: 因爲數據編碼的不同,而有了對字符進行高效操作的流對象。本質其實就是基於字節流讀取時,去查了指定的碼錶。字節流和字符流的區別:
(1)讀寫單位不同:字節流以字節(8bit)爲單位,字符流以字符爲單位,根據碼錶映射字符,一次可能讀多個字節。
(2)處理對象不同:字節流能處理所有類型的數據(如圖片、avi等),而字符流只能處理字符類型的數據。
(3)字節流在操作的時候本身是不會用到緩衝區的,是文件本身的直接操作的;而字符流在操作的時候下後是會用到緩衝區的,是通過緩衝區來操作文件,我們將在下面驗證這一點。

結論:優先選用字節流。首先因爲硬盤上的所有文件都是以字節的形式進行傳輸或者保存的,包括圖片等內容。但是字符只是在內存中才會形成的,所以在開發中,字節流使用廣泛。
輸入流和輸出流
對輸入流只能進行讀操作,對輸出流只能進行寫操作,程序中需要根據待傳輸數據的不同特性而使用不同的流。

三、字節流讀寫操作

3.1、按字節流讀文件

InputStream 

此抽象類是表示字節輸入流的所有類的超類。需要定義 InputStream 的子類的應用程序必須始終提供返回下一個輸入字節的方法。 
int available() 
返回此輸入流方法的下一個調用方可以不受阻塞地從此輸入流讀取(或跳過)的字節數。 
void close() 
關閉此輸入流並釋放與該流關聯的所有系統資源。 
void mark(int readlimit) 
在此輸入流中標記當前的位置。 
boolean markSupported() 
測試此輸入流是否支持 mark 和 reset 方法。 
abstract int read() 
從輸入流讀取下一個數據字節。 
int read(byte[] b) 
從輸入流中讀取一定數量的字節並將其存儲在緩衝區數組 b 中。 
int read(byte[] b, int off, int len) 
將輸入流中最多 len 個數據字節讀入字節數組。 
void reset() 
將此流重新定位到對此輸入流最後調用 mark 方法時的位置。 
long skip(long n) 
跳過和放棄此輸入流中的 n 個數據字節

其類圖如下:


使用實例如下:

[java] view plaincopy
  1. package com.lin;  
  2.   
  3. import java.io.File;  
  4. import java.io.FileInputStream;  
  5. import java.io.FileNotFoundException;  
  6. import java.io.IOException;  
  7. import java.io.InputStream;  
  8.   
  9. /** 
  10.  * 功能概要:字節流讀取文件 
  11.  *  
  12.  * @author linbingwen 
  13.  * @since 2015年9月5日 
  14.  */  
  15. public class Test1 {  
  16.   
  17.     /** 
  18.      * @author linbingwen 
  19.      * @since 2015年9月5日 
  20.      * @param args 
  21.      * @throws IOException 
  22.      */  
  23.     public static void main(String[] args) {  
  24.         String path = "D:" + File.separator + "test1.txt";  
  25.         readFile1(path);  
  26.         readFile2(path);  
  27.   
  28.     }  
  29.       
  30.     /** 
  31.      * 字節流讀取文件:單個字符讀取 
  32.      * @author linbingwen 
  33.      * @since  2015年9月5日  
  34.      * @param path 
  35.      */  
  36.     public static void readFile1(String path) {  
  37.         FileInputStream is = null;  
  38.         try {  
  39.             is = new FileInputStream(path);  
  40.             System.out.println("===============================單個字符讀取begin===============================");  
  41.             int ch = 0;  
  42.             while ((ch = is.read()) != -1) {  
  43.                 System.out.print((char) ch);  
  44.             }  
  45.             System.out.println();  
  46.             System.out.println("===============================單個字符讀取end===============================");        
  47.         } catch (IOException e) {  
  48.             e.printStackTrace();  
  49.         } finally {  
  50.             // 關閉輸入流  
  51.             if (is != null) {  
  52.                 try {  
  53.                     is.close();  
  54.                 } catch (IOException e) {  
  55.                     e.printStackTrace();  
  56.                 }  
  57.             }  
  58.         }  
  59.     }  
  60.     /** 
  61.      * 字節流讀取文件:數組循環讀取 
  62.      * @author linbingwen 
  63.      * @since  2015年9月5日  
  64.      * @param path 
  65.      */  
  66.     public static void readFile2(String path) {  
  67.         FileInputStream is = null;  
  68.         try {  
  69.             // 創建文件輸入流對象  
  70.             is = new FileInputStream(path);  
  71.             // 設定讀取的字節數  
  72.             int n = 512;  
  73.             byte buffer[] = new byte[n];  
  74.             // 讀取輸入流  
  75.             System.out.println("===============================數組循環讀取begin===============================");  
  76.             while ((is.read(buffer, 0, n) != -1) && (n > 0)) {  
  77.                 System.out.print(new String(buffer));  
  78.             }  
  79.             System.out.println();  
  80.             System.out.println("===============================數組循環讀取end===============================");  
  81.         } catch (IOException ioe) {  
  82.             System.out.println(ioe);  
  83.         } catch (Exception e) {  
  84.             System.out.println(e);  
  85.         } finally {  
  86.             // 關閉輸入流  
  87.             if (is != null) {  
  88.                 try {  
  89.                     is.close();  
  90.                 } catch (IOException e) {  
  91.                     e.printStackTrace();  
  92.                 }  
  93.             }  
  94.         }  
  95.     }  
  96.   
  97. }  

test1.txt內容如下:



程序運行結果:


注意:對於中文字符,會出現亂碼,中文字符要用字符流來讀取

如果把內容改成如下:



輸出結果如下:


可以看到,中文確實變成亂碼了,這就是按字節讀取的壞處。

3.2、按字節流寫文件

OutputStream 
此抽象類是表示輸出字節流的所有類的超類。輸出流接受輸出字節並將這些字節發送到某個接收器。需要定義OutputStream 子類的應用程序必須始終提供至少一種可寫入一個輸出字節的方法。 
void close() 
關閉此輸出流並釋放與此流有關的所有系統資源。 
void flush() 
刷新此輸出流並強制寫出所有緩衝的輸出字節。 
void write(byte[] b) 
將 b.length 個字節從指定的字節數組寫入此輸出流。 
void write(byte[] b, int off, int len) 
將指定字節數組中從偏移量 off 開始的 len 個字節寫入此輸出流。 
abstract void write(int b) 
將指定的字節寫入此輸出流。 
進行I/O操作時可能會產生I/O例外,屬於非運行時例外,應該在程序中處理。如:FileNotFoundException, EOFException, IOException等等,下面具體說明操作JAVA字節流的方法。 

其類圖如下:


使用實例如下:

[java] view plaincopy
  1. package com.lin;  
  2.   
  3. import java.io.File;  
  4. import java.io.FileInputStream;  
  5. import java.io.FileOutputStream;  
  6.   
  7. /** 
  8.  * 功能概要: 
  9.  *  
  10.  * @author linbingwen 
  11.  * @since 2015年9月5日 
  12.  */  
  13. public class Test2 {  
  14.   
  15.     /** 
  16.      * @author linbingwen 
  17.      * @since 2015年9月5日 
  18.      * @param args 
  19.      */  
  20.     public static void main(String[] args) {  
  21.         String input = "D:" + File.separator + "hello.jpg";  
  22.         String output = "D:" + File.separator + "hello1.jpg";  
  23.         writeFile(input,output);  
  24.   
  25.     }  
  26.   
  27.     /** 
  28.      * 文件複製操作,可以是圖片、文字 
  29.      *  
  30.      * @author linbingwen 
  31.      * @since 2015年9月5日 
  32.      * @param input 
  33.      * @param output 
  34.      */  
  35.     public static void writeFile(String input, String output) {  
  36.         FileInputStream fis = null;  
  37.         FileOutputStream fos = null;  
  38.         byte[] buffer = new byte[100];  
  39.         int temp = 0;  
  40.         try {  
  41.             fis = new FileInputStream(input);  
  42.             fos = new FileOutputStream(output);  
  43.             while (true) {  
  44.                 temp = fis.read(buffer, 0, buffer.length);  
  45.                 if (temp == -1) {  
  46.                     break;  
  47.                 }  
  48.                 fos.write(buffer, 0, temp);  
  49.             }  
  50.         } catch (Exception e) {  
  51.             System.out.println(e);  
  52.         } finally {  
  53.             try {  
  54.                 fis.close();  
  55.                 fos.close();  
  56.             } catch (Exception e2) {  
  57.                 System.out.println(e2);  
  58.             }  
  59.         }  
  60.   
  61.     }  
  62. }  
運行結果:


還可以進行MP3的寫!

四、字符流讀寫操作

4.1、字符流讀取操作

        java採用16位的Unicode來表示字符串和字符,對應的數據流就稱爲字符流。Reader和Writer爲字符流設計。FileReader是InputStreamReader的子類,而InputStreamReader是Reader的子類;FileWriter是OutputStreamWriter的子類,而OutputStreamWriter則是Writer的子類。字符流和字節流的區別在於,字符流操作的對象是字符及字符數組,而字節流操作的對象則是字節及字節數組。
字符輸入流
FileReader的常用構造包括以下幾種。
FileReader(String fileName):根據文件名創建FileReader對象。
FileReader(File file):根據File對象創建FileReader對象。
FileReader的常用方法包括以下幾種。
int read():讀取單個字符。返回字符的整數值,如果已經到達文件尾,則返回-1.
int read(char[] cbuf):將字符讀入cbuf字符數組。返回讀取到的字符數,如果已經到達文件尾,則返回-1.
int read(char[] cbuf,int off,int len):將讀取到的字符存放到cbuf字符數組從off標識的偏移位置開始處,最多讀取len個字符。
與字節流不同,BufferReader是Reader的直接子類,這一點和BufferInputStream是InputStream的二級子類有所不同。通過BufferReader.readLine()方法可以實現讀取文本行、返回字符串,因爲我們平時讀取的文本文件大多是斷行的,而且該方法能直接返回字符串,因此BufferReader使用得比FileReader更爲廣泛。
BufferReader用有以下兩種構造方法。
BufferReader(Reader in):根據in代表的Reader對象創建BufferReader實例,緩衝區大小採用默認值。
BufferReader(Reader in,int sz):根據in代表的Reader對象創建BufferReader實例,緩衝區大小採用指定sz值。
BufferReader.readLine()方法遇到以下字符或者字符串認爲當前行結束:‘\n’(換行符),'\r'(回車符),'\r\n'(回車換行)。返回值爲該行內容的字符串,不包含任何行終止符,如果已到達流末尾,則返回null。

其類圖如下:


實例代碼如下:

[java] view plaincopy
  1. package com.lin;  
  2. import java.io.BufferedReader;  
  3. import java.io.File;  
  4. import java.io.FileInputStream;  
  5. import java.io.FileNotFoundException;  
  6. import java.io.FileReader;  
  7. import java.io.IOException;  
  8. import java.io.InputStreamReader;  
  9.   
  10. /** 
  11.  * 功能概要:字符流讀取操作 
  12.  *  
  13.  * @author linbingwen 
  14.  * @since 2015年9月5日 
  15.  */  
  16. public class Test3 {  
  17.   
  18.     /** 
  19.      * @author linbingwen 
  20.      * @since 2015年9月5日 
  21.      * @param args 
  22.      */  
  23.     public static void main(String[] args) {  
  24.         String path = "D:" + File.separator + "test3.txt";  
  25.         readFile1(path);  
  26.         readFile2(path);  
  27.         readFile3(path,"utf-8");  
  28.   
  29.     }  
  30.       
  31.     /** 
  32.      * 字符流讀取文件方法一 
  33.      * @author linbingwen 
  34.      * @since  2015年9月5日  
  35.      * @param path 
  36.      */  
  37.     public static void readFile1(String path) {  
  38.         FileReader r = null;  
  39.         try {  
  40.             r = new FileReader(path);  
  41.             // 讀入到字符數組的優化  
  42.             // 由於有時候文件太大,無法確定需要定義的數組大小  
  43.             // 因此一般定義數組長度爲1024,採用循環的方式讀入  
  44.             char[] buf = new char[1024];  
  45.             int temp = 0;  
  46.             System.out.println("========================== 字符流讀取文件方法一==========================");  
  47.             while ((temp = r.read(buf)) != -1) {  
  48.                 System.out.print(new String(buf, 0, temp));  
  49.             }  
  50.             System.out.println();  
  51.         } catch (IOException e) {  
  52.             e.printStackTrace();  
  53.         } finally {  
  54.             if (r != null) {  
  55.                 try {  
  56.                     r.close();  
  57.                 } catch (IOException e) {  
  58.                     e.printStackTrace();  
  59.                 }  
  60.             }  
  61.         }  
  62.     }  
  63.   
  64.     /** 
  65.      * 字符流讀取文件方法二 
  66.      * @author linbingwen 
  67.      * @since  2015年9月5日  
  68.      * @param path 
  69.      * @return 
  70.      */  
  71.     public static String readFile2(String path) {  
  72.         File file = new File(path);  
  73.         StringBuffer sb = new StringBuffer();  
  74.         if (file.isFile()) {  
  75.             BufferedReader bufferedReader = null;  
  76.             FileReader fileReader = null;  
  77.             try {  
  78.                 fileReader = new FileReader(file);  
  79.                 bufferedReader = new BufferedReader(fileReader);  
  80.                 String line = bufferedReader.readLine();  
  81.                 System.out.println("========================== 字符流讀取文件方法二==========================");  
  82.                 while (line != null) {  
  83.                     System.out.println(line);  
  84.                     sb.append(line + "\r\n");  
  85.                     line = bufferedReader.readLine();  
  86.                 }  
  87.             } catch (FileNotFoundException e) {  
  88.                 e.printStackTrace();  
  89.             } catch (IOException e) {  
  90.                 e.printStackTrace();  
  91.             } finally {  
  92.                 try {  
  93.                     fileReader.close();  
  94.                     bufferedReader.close();  
  95.                 } catch (IOException e) {  
  96.                     e.printStackTrace();  
  97.                 }  
  98.             }  
  99.   
  100.         }  
  101.         return sb.toString();  
  102.     }  
  103.       
  104.     /** 
  105.      * 字符流讀取文件:可以指定文件編碼格式 
  106.      * @author linbingwen 
  107.      * @since  2015年9月5日  
  108.      * @param path 
  109.      * @param charset 
  110.      * @return 
  111.      */  
  112.     public static String readFile3(String path,String charset) {  
  113.         File file = new File(path);  
  114.         StringBuffer sb = new StringBuffer();  
  115.         if (file.isFile()) {  
  116.             BufferedReader bufferedReader = null;  
  117.             InputStreamReader inputStreamReader = null;  
  118.             try {  
  119.                 inputStreamReader = new InputStreamReader(new FileInputStream(file), charset);  
  120.                 bufferedReader = new BufferedReader(inputStreamReader);  
  121.                 String line = bufferedReader.readLine();  
  122.                 System.out.println("========================== 字符流讀取文件方法三==========================");  
  123.                 while (line != null) {  
  124.                     System.out.println(line);  
  125.                     sb.append(line + "\r\n");  
  126.                     line = bufferedReader.readLine();  
  127.                 }  
  128.             } catch (FileNotFoundException e) {  
  129.                 e.printStackTrace();  
  130.             } catch (IOException e) {  
  131.                 e.printStackTrace();  
  132.             } finally {  
  133.                 try {  
  134.                     inputStreamReader.close();  
  135.                     bufferedReader.close();  
  136.                 } catch (IOException e) {  
  137.                     e.printStackTrace();  
  138.                 }  
  139.             }  
  140.   
  141.         }  
  142.         return sb.toString();  
  143.     }  
  144.   
  145.       
  146.   
  147. }  
這是運行結果:


其中,第三種方法如果指定編碼後結果如下:
[java] view plaincopy
  1. readFile3(path,"GBK");  

可以看到,中文變成亂碼了。

4.2、按字符寫入

字符輸出流
FileWriter的常用構造有以下幾種。
FileWriter(String fileName):根據文件名創建FileWriter對象。
FileWriter(String fileName,boolean append):根據文件名創建FileWriter對象,append參數用來指定是否在原文件之後追加內容。
FileWriter(File file):根據File對象創建FileWriter對象。
FileWriter(File file,boolean append):根據File對象創建FileWriter對象,append參數用來指定是否在原文件之後追加內容。
FileWriter的常用方法包括以下幾種。
void writer(int c):向文件中寫入正整數c代表的單個字符。
void writer(char[] cbuf):向文件中寫入字符數組cbuf。
void writer(char[] cbuf,int off, in len):向文件中寫入字符數組cbuf從偏移位置off開始的len個字符。
void writer(String str):向文件中寫入字符串str,注意此方法不會在寫入完畢之後自動換行。
void writer(String str,int off,int len):向文件中寫入字符串str的從位置off開始、長度爲len的一部分子串。
Writer append(char c):向文件中追加單個字符c。
Writer append(CharSequence csq):向文件中追加csq代表的一個字符序列。CharSequence是從JDK1.4版本開始引入的一個接口,代表字符值的一個可讀序列,此接口對許多不同種類的字符序列提供統一的只讀訪問。
Writer append(CharSequence csq,int start,int end):向文件中追加csq字符序列的從位置start開始、end結束的一部分字符。
void flush():刷新字符輸出流緩衝區。
void close():關閉字符輸出流。
和BufferReader相對應,啓用緩衝區的BufferWriter也擁有一下兩種形式的構造方法。
BufferWriter(Writer out): 根據out代表的Writer對象創建BufferWriter實例,緩衝區大小採用默認值。
BufferWriter(Writer out,int sz):根據out代表的Writer對象創建BufferWriter實例,緩衝區大小採用指定的sz值。
我們知道,BufferReader類的readLine()方法能一次從輸入流中讀入一行,但對於BufferWriter類,卻沒有一次寫一行的方法。若要向輸出流中一次寫一行,可用PrintWriter類(PrintWriter也是Writer的直接子類)將原來的流改造成新的打印流,PrintWriter類有一個方法println(String),能一次輸出一行,即在待輸出的字符串後自動補“\r\n”.
其類圖如下:

實例代碼如下:
[java] view plaincopy
  1. package com.lin;  
  2.   
  3. import java.io.BufferedWriter;  
  4. import java.io.File;  
  5. import java.io.FileWriter;  
  6. import java.io.IOException;  
  7.   
  8. /** 
  9.  * 功能概要: 
  10.  *  
  11.  * @author linbingwen 
  12.  * @since  2015年9月5日  
  13.  */  
  14. public class Test4 {  
  15.   
  16.     /** 
  17.      * @author linbingwen 
  18.      * @since  2015年9月5日  
  19.      * @param args     
  20.      */  
  21.     public static void main(String[] args) {  
  22.         String path = "D:" + File.separator + "test4.txt";  
  23.         String str= "Evankaka林炳文Evankaka林炳文Evankaka林炳文\r\n";  
  24.         writeFile(path,str);  
  25.         writeFile(path,str);  
  26.         writeFile(path,str);  
  27.     }  
  28.       
  29.     /** 
  30.      * 利用字符流寫入文件 
  31.      * @author linbingwen 
  32.      * @since  2015年9月5日  
  33.      * @param path 
  34.      * @param content 
  35.      */  
  36.     public static void writeFile(String path,String content){  
  37.         //由於IO操作會拋出異常,因此在try語句塊的外部定義FileWriter的引用  
  38.         FileWriter w = null;  
  39.         try {  
  40.             //以path爲路徑創建一個新的FileWriter對象  
  41.             //如果需要追加數據,而不是覆蓋,則使用FileWriter(path,true)構造方法  
  42.             //w = new FileWriter(path,true);        
  43.             w = new FileWriter(path,true);             
  44.             //將字符串寫入到流中,\r\n表示換行  
  45.             w.write(content);  
  46.             //如果想馬上看到寫入效果,則需要調用w.flush()方法  
  47.             w.flush();  
  48.         } catch (IOException e) {  
  49.             e.printStackTrace();  
  50.         } finally {  
  51.             //如果前面發生異常,那麼是無法產生w對象的  
  52.             //因此要做出判斷,以免發生空指針異常  
  53.             if(w != null) {  
  54.                 try {  
  55.                     //關閉流資源,需要再次捕捉異常  
  56.                     w.close();  
  57.                 } catch (IOException e) {  
  58.                     e.printStackTrace();  
  59.                 }  
  60.             }  
  61.         }  
  62.     }  
  63.       
  64.   
  65.   
  66. }  

寫入的文件內容如下:

參考文章:
http://developer.51cto.com/art/201309/410902.htm
http://www.ibm.com/developerworks/cn/java/j-lo-javaio/

版權聲明:本文爲博主林炳文Evankaka原創文章,轉載請註明出處http://blog.csdn.net/evankaka

發佈了28 篇原創文章 · 獲贊 1 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章