IO流操作詳解

木叔發表於2016-05-04

 注:FileReader繼承InputStreamReader類,InputStreamReader實現Reader介面,其他同理。

對於檔案內容的操作主要分為兩大類

分別是:

  字元流

  位元組流

其中,字元流有兩個抽象類:Writer   Reader

其對應子類FileWriter和FileReader可實現檔案的讀寫操作

BufferedWriter和BufferedReader能夠提供緩衝區功能,用以提高效率

 

同樣,位元組流也有兩個抽象類:InputStream   OutputStream

其對應子類有FileInputStream和FileOutputStream實現檔案讀寫

BufferedInputStream和BufferedOutputStream提供緩衝區功能

 

字元流和位元組流的主要區別:

       1.位元組流讀取的時候,讀到一個位元組就返回一個位元組;  字元流使用了位元組流讀到一個或多個位元組(中文對應的位元組數是兩個,在UTF-8碼錶中是3個位元組)時。先去查指定的編碼表,將查到的字元返回。

       2.位元組流可以處理所有型別資料,如:圖片,MP3,AVI視訊檔案,而字元流只能處理字元資料。只要是處理純文字資料,就要優先考慮使用字元流,除此之外都用位元組流。

注意:

讀寫流使用完都要用.close方法關閉,防止佔用資源,但是在關閉之前防止空值最好做空值判斷再關閉;進行寫操作時想立即生效用write.flush()重新整理。

注意寫檔案路徑時碟符後面用\\或者/,如:c:\\demo.txt或者c:/demo.txt

BufferedReader特有方法:readLine(),將行標記之前的資料作為字串返回,讀到結尾時返回null,讀取行是將讀取的字元臨時儲存產生的效果。

具體操作方法如下:

 

FileReader(字元流的讀取)
            FileReader r
new FileReader(path);                           //方式一:讀取單個字元的方式             //每讀取一次,向下移動一個字元單位,返回讀取的位元組數             int temp1 = r.read();             System.out.println((char)temp1);             int temp2 = r.read();             System.out.println((char)temp2);                                       //方式二:迴圈讀取             //read()方法讀到檔案末尾會返回-1             /*             while (true) {                 int temp = r.read();                 if (temp == -1) {                     break;                 }                 System.out.print((char)temp);             }             */                           //方式三:迴圈讀取的簡化操作             //單個字元讀取,當temp不等於-1的時候列印字元             /*int temp = 0;             while ((temp = r.read()) != -1) {                 System.out.print((char)temp);             }             */                           //方式四:讀入到字元陣列             /*             char[] buf = new char[1024];             int temp = r.read(buf);             //將陣列轉化為字串列印,後面引數的意思是             //如果字元陣列未滿,轉化成字串列印後尾部也許會出現其他字元             //因此,讀取的字元有多少個,就轉化多少為字串             System.out.println(new String(buf,0,temp));             */                           //方式五:讀入到字元陣列的優化             //由於有時候檔案太大,無法確定需要定義的陣列大小             //因此一般定義陣列長度為1024,採用迴圈的方式讀入             /*             char[] buf = new char[1024];             int temp = 0;             while((temp = r.read(buf)) != -1) {                 System.out.print(new String(buf,0,temp));             }             */ FileWriter(字元流的寫入)     String path="E:\\demo.txt";     //由於IO操作會丟擲異常,因此在try語句塊的外部定義FileWriter的引用         FileWriter w = null;         try {             //以path為路徑建立一個新的FileWriter物件             //如果需要追加資料,而不是覆蓋,則使用FileWriter(path,true)構造方法             w = new FileWriter(path);             //將字串寫入到流中,\r\n表示換行想有好的             w.write("Nerxious is a good boy\r\n");             //如果想馬上看到寫入效果,則需要呼叫w.flush()方法             w.flush();         } catch (IOException e) {             e.printStackTrace();         } finally {             //如果前面發生異常,那麼是無法產生w物件的             //因此要做出判斷,以免發生空指標異常             if(w != null) {                 try {                     //關閉流資源,需要再次捕捉異常                     w.close();                 } catch (IOException e) {                     e.printStackTrace();                 }             }         } 即FileWriter w = new FileWriter(path);//指定寫的路徑 w.write("Nerxious is a good boy\r\n");//寫入具體內容 文字檔案的複製        String doc=”...”;        String copy=”...”:             FileReader rnew FileReader(doc);             FileWriter w new FileWriter(copy);                           //方式一:單個字元寫入             int temp = 0;             while((temp = r.read()) != -1) {                 w.write(temp);             }                           //方式二:字元陣列方式寫入             /*             char[] buf = new char[1024];             int temp = 0;             while ((temp = r.read(buf)) != -1) {                 w.write(new String(buf,0,temp));             }             */ 利用字元流的緩衝區來進行文字檔案的複製             FileReader r new FileReader(doc);             FileWriter w new FileWriter(copy);             //建立緩衝區物件             //將需要提高效率的FileReader和FileWriter物件放入其建構函式內             //當然,也可以使用匿名物件的方式 br = new BufferedReader(new FileReader(doc));             BufferedReader br = new BufferedReader(r);             BufferedWriter bw new BufferedWriter(w);                          String line null;             //讀取行,直到返回null             //readLine()方法只返回換行符之前的資料             while((line = br.readLine()) != null) {                 //使用BufferWriter物件的寫入方法                 bw.write(line);                 //寫完檔案內容之後換行                 //newLine()方法依據平臺而定                 //windows下的換行是\r\n                 //Linux下則是\n                 bw.newLine(); } 位元組流:        FileOutputStream(字元流的寫入)        FileOutputStream o new FileOutputStream(path);             String str = "Nerxious is a good boy\r\n";             byte[] buf = str.getBytes();             //也可以直接使用o.write("String".getBytes());             //因為字串就是一個物件,能直接呼叫方法             o.write(buf); FileInputStream(位元組流的讀取)        FileInputStream i new FileInputStream(path);                           //方式一:單個字元讀取             //需要注意的是,此處我用英文文字測試效果良好             //但中文就悲劇了,不過下面兩個方法效果良好             int ch = 0;             while((ch=i.read()) != -1){                 System.out.print((char)ch);             }                           //方式二:陣列迴圈讀取             /*             byte[] buf = new byte[1024];             int len = 0;             while((len = i.read(buf)) != -1) {                 System.out.println(new String(buf,0,len));             }             */                           //方式三:標準大小的陣列讀取             /*             //定一個一個剛好大小的陣列             //available()方法返回檔案的位元組數             //但是,如果檔案過大,記憶體溢位,那就悲劇了             //所以,親們要慎用!!!上面那個方法就不錯             byte[] buf = new byte[i.available()];             i.read(buf);             //因為陣列大小剛好,所以轉換為字串時無需在建構函式中設定起始點             System.out.println(new String(buf));             */ 二進位制檔案(即非純文字檔案)的複製      Bin/copy為 檔案路徑,“E:\\demo.mp3”,此處示例檔案為mp3檔案      FileInputStream i null;         FileOutputStream o null;                   try {             i new FileInputStream(bin);             o new FileOutputStream(copy);                           //迴圈的方式讀入寫出檔案,從而完成複製             byte[] buf = new byte[1024];             int temp = 0;             while((temp = i.read(buf)) != -1) {                 o.write(buf, 0, temp);             } 利用位元組流的緩衝區進行二進位制檔案的複製      FileInputStream i null;         FileOutputStream o null;         BufferedInputStream bi null;         BufferedOutputStream bo null;                   try {             i new FileInputStream(bin);             o new FileOutputStream(copy);             bi new BufferedInputStream(i);             bo new BufferedOutputStream(o);                           byte[] buf = new byte[1024];             int temp = 0;             while((temp = bi.read(buf)) != -1) {                 bo.write(buf,0,temp);             } 檔案的操作 遞迴列出目錄下所有檔案 File f new File(path); //方式一:list()         //返回一個包含指定目錄下所有檔名的字串陣列         //如果不是一個目錄則返回null         String[] files = f.list();         for (String x : files) {             System.out.println(x);         } //方式二: if(f.isDirectory()){             File[] files = f.listFiles();             for(File x : files) {                 print(x);             }         }  兩者都是返回目錄下的所有檔名,但是第二種方式更實用,為遞迴列出檔案做鋪墊 列出根目錄: //listRoots()是一個靜態方法,返回檔案陣列         File[] files = File.listRoots();         //foreach迴圈列印File物件         for (File x : files) {             System.out.println(x);         } 本地環境是Linux,所以根目錄只有一個 /,如果是Windows就能列出你的所有碟符 Scanner類: 從鍵盤讀取 Scanner input new Scanner(System.in);             System.out.println("請輸出一個整數:");         int i = input.nextInt();         System.out.println("你輸入的整數是:" + i); 從字串讀取 Scanner input new Scanner("hello\r\nworld\r\n");         //迴圈讀取,hasNext()方法和集合框架裡面的一樣使         while(input.hasNext()) {             //每次讀取一行,別的讀取方法見API,比較簡單             String s = input.nextLine();             System.out.println(s);         }   從檔案讀取: File f new File(path);             //從檔案構造Scanner物件,有可能產生異常             Scanner input = new Scanner(f);             while(input.hasNext()) {                 String s = input.nextLine();                 System.out.println(s);             } PrintWriter類 向檔案寫入內容 File file new File(path);             //此處建構函式還可以傳其他物件,具體參考API文件             PrintWriter p = new PrintWriter(file);                           //向檔案寫入一行,此外還有print()和printf()方法             p.println("如果有一天我回到從前");             p.println("回到最原始的我");             p.println("你是否會覺得我不錯");                           //重新整理流             p.flush(); 與PrintWriter類似的還有一個PrintStream類,此處以PrintWriter舉例是因為文字檔案具有人為可讀性,而二進位制檔案(位元組模式)則需要使用專門的程式來讀取.可能有人會問:FileOutputStream、 FileWriter都能寫檔案,那麼為何還需要PrintWriter和PrintStream類,如果細看API文件,可以知道前者單純的字元寫入流和位元組寫入流操作的方式大多用陣列進行,對檔案的細化處理非常不方便,而PrintWriter和PrintStream則很好的解決了這一問題,提供print()等方法,並且,PrintWriter和PrintStream對於不存在檔案物件的情況下會直接建立,如果已有檔案物件,它們則會把原有檔案給覆蓋掉,卻沒有增加方法。解決這問題也很簡單,再看API文件,PrintWriter有一個構造方法PrintWriter(Writer out),也就是能夠傳入Writer物件,PrintStream有一個構造方法PrintStream(OutputStream out),也就是能傳入OutputStream物件。因此,我們這樣寫就可以了 new PrintWriter(new FileWriter(file,true)) new PrintStream(new FileOutputStream(file,true)) 既能增加資料,也能更高效的處理檔案,見如下程式碼示範        File file new File(path);             //利用FileWriter方式構建PrintWriter物件,實現追加             PrintWriter p = new PrintWriter(new FileWriter(file,true));             p.println("尼瑪 這一句就是追加的 看到沒");             p.flush(); System類相關: //別忘了,OutputStream是所有位元組寫入流的父類         OutputStream out = System.out;             //寫入資料,只能是陣列,所以用getBytes()方法             out.write("Hello,bitch!\r\n".getBytes()); System類中的讀取 InputStream in = System.in;         System.out.print("請輸入文字: ");         byte[] buf = new byte[1024];         int len = 0;             //將輸入的資料保證到陣列中,len記錄輸入的長度             len = in.read(buf);                  //用字串的方式列印陣列中的資料         System.out.println("你的輸入是: " + new String(buf,0,len)); 利用BufferedReader實現對鍵盤的讀取  BufferedReader b new BufferedReader(new InputStreamReader(System.in));         System.out.print("請輸入文字:");             String str = b.readLine();             System.out.println("你輸入的是:" + str);                   //迴圈讀取方式         /*         while(true) {             System.out.print("請輸入文字:");             String str = b.readLine();             //如果輸入over就結束迴圈             if("over".equals(str)) {                 break;             }             System.out.println("你輸入的是:" + str);