我的以爲能夠用「字節流操做類和字符流操做類組成了Java IO體系」來高度歸納Java IO體系。java
借用幾張網絡圖片來講明(圖片來自 http://blog.csdn.net/zhangerqing/article/details/8466532 )編程
![]()
|
![]()
|
![]()
|
![]()
|
從上圖能夠看到,整個Java IO體系都是基於字符流(InputStream/OutputStream) 和 字節流(Reader/Writer)做爲基類,根據不一樣的數據載體或功能派生出來的。數組
這四個類是專門操做文件流的,用法高度類似,區別在於前面兩個是操做字節流,後面兩個是操做字符流。它們都會直接操做文件流,直接與OS底層交互。所以他們也被稱爲節點流。安全
注意使用這幾個流的對象以後,須要關閉流對象,由於java垃圾回收器不會主動回收。不過在Java7以後,能夠在 try() 括號中打開流,最後程序會自動關閉流對象,再也不須要顯示地close。網絡
下面演示這四個流對象的基本用法,less
1 package io; 2 3 import java.io.FileInputStream; 4 import java.io.FileNotFoundException; 5 import java.io.FileOutputStream; 6 import java.io.FileReader; 7 import java.io.FileWriter; 8 import java.io.IOException; 9 10 public class TestIO { 11 public static void FileInputStreamTest() throws IOException { 12 FileInputStream fis = new FileInputStream("tmp2.txt"); 13 byte[] buf = new byte[1024]; 14 int hasRead = 0; 15 16 //read()返回的是單個字節數據(字節數據能夠直接專程int類型),可是read(buf)返回的是讀取到的字節數,真正的數據保存在buf中 17 while ((hasRead = fis.read(buf)) > 0) { 18 //每次最多將1024個字節轉換成字符串,這裏tmp2.txt中的字符小於1024,因此一次就讀完了 19 //循環次數 = 文件字符數 除以 buf長度 20 System.out.println(new String(buf, 0 ,hasRead)); 21 /* 22 * 將字節強制轉換成字符後逐個輸出,能實現和上面同樣的效果。可是若是源文件是中文的話可能會亂碼 23 24 for (byte b : buf) { 25 char ch = (char)b; 26 if (ch != '\r') 27 System.out.print(ch); 28 } 29 */ 30 } 31 //在finally塊裏close更安全 32 fis.close(); 33 } 34 35 public static void FileReaderTest() throws IOException { 36 37 try ( 38 // 在try() 中打開的文件, JVM會自動關閉 39 FileReader fr = new FileReader("tmp2.txt")) { 40 char[] buf = new char[32]; 41 int hasRead = 0; 42 // 每一個char都佔兩個字節,每一個字符或者漢字都是佔2個字節,所以不管buf長度爲多少,老是能讀取中文字符長度的整數倍,不會亂碼 43 while ((hasRead = fr.read(buf)) > 0) { 44 // 若是buf的長度大於文件每行的長度,就能夠完整輸出每行,不然會斷行。 45 // 循環次數 = 文件字符數 除以 buf長度 46 System.out.println(new String(buf, 0, hasRead)); 47 // 跟上面效果同樣 48 // System.out.println(buf); 49 } 50 } catch (IOException ex) { 51 ex.printStackTrace(); 52 } 53 } 54 55 public static void FileOutputStreamTest() throws FileNotFoundException, IOException { 56 try ( 57 //在try()中打開文件會在結尾自動關閉 58 FileInputStream fis = new FileInputStream("tmp2.txt"); 59 FileOutputStream fos = new FileOutputStream("tmp3.txt"); 60 ) { 61 byte[] buf = new byte[4]; 62 int hasRead = 0; 63 while ((hasRead = fis.read(buf)) > 0) { 64 //每讀取一次就寫一次,讀多少就寫多少 65 fos.write(buf, 0, hasRead); 66 } 67 System.out.println("write success"); 68 } catch (IOException e) { 69 e.printStackTrace(); 70 } 71 } 72 73 public static void FileWriterTest() throws IOException { 74 try (FileWriter fw = new FileWriter("tmp4.txt")) { 75 fw.write("天王蓋地虎\r\n"); 76 fw.write("寶塔鎮河妖\r\n"); 77 } catch (IOException e) { 78 e.printStackTrace(); 79 } 80 } 81 public static void main(String[] args) throws IOException { 82 //FileInputStreamTest(); 83 //FileReaderTest(); 84 //FileOutputStreamTest(); 85 FileWriterTest(); 86 } 87 }
PrintStream能夠封裝(包裝)直接與文件交互的節點流對象OutputStream, 使得編程人員能夠忽略設備底層的差別,進行一致的IO操做。所以這種流也稱爲處理流或者包裝流。性能
PrintWriter除了能夠包裝字節流OutputStream以外,還能包裝字符流Writerspa
Scanner能夠包裝鍵盤輸入,方便地將鍵盤輸入的內容轉換成咱們想要的數據類型。.net
這兩個操做的是專門操做String字符串的流,其中StringReader能從String中方便地讀取數據並保存到char數組,而StringWriter則將字符串類型的數據寫入到StringBuffer中(由於String不可寫)。code
這兩個類能夠將字節流轉換成字符流,被稱爲字節流與字符流之間的橋樑。咱們常常在讀取鍵盤輸入(System.in)或網絡通訊的時候,須要使用這兩個類
Oracle官方的描述:
Most of the examples we've seen so far use unbuffered I/O. This means each read or write request is handled directly by the underlying OS. This can make a program much less efficient.
Buffered input streams read data from a memory area known as a buffer; the native input API is called only when the buffer is empty. Similarly, buffered output streams write data to a buffer, and the native output API is called only when the buffer is full.
即,
沒有通過Buffered處理的IO, 意味着每一次讀和寫的請求都會由OS底層直接處理,這會致使很是低效的問題。
通過Buffered處理過的輸入流將會從一個buffer內存區域讀取數據,本地API只會在buffer空了以後纔會被調用(可能一次調用會填充不少數據進buffer)。
通過Buffered處理過的輸出流將會把數據寫入到buffer中,本地API只會在buffer滿了以後纔會被調用。
BufferedReader/BufferedWriter能夠將字符流(Reader)包裝成緩衝流,這是最多見用的作法。
另外,BufferedReader提供一個readLine()能夠方便地讀取一行,而FileInputStream和FileReader只能讀取一個字節或者一個字符,
所以BufferedReader也被稱爲行讀取器
下面演示上面提到的常見類,
1 package io; 2 3 import java.io.BufferedReader; 4 import java.io.FileInputStream; 5 import java.io.FileNotFoundException; 6 import java.io.FileOutputStream; 7 import java.io.FileReader; 8 import java.io.IOException; 9 import java.io.InputStreamReader; 10 import java.io.PrintStream; 11 import java.io.PushbackReader; 12 import java.io.StringReader; 13 import java.io.StringWriter; 14 15 public class TestIO { 16 public static void printStream() throws FileNotFoundException, IOException { 17 try ( 18 FileOutputStream fos = new FileOutputStream("tmp.txt"); 19 PrintStream ps = new PrintStream(fos)) { 20 ps.println("普通字符串\n"); 21 //輸出對象 22 ps.println(new TestIO()); 23 } catch (IOException e) { 24 e.printStackTrace(); 25 } 26 System.out.println("輸出完成"); 27 28 } 29 public static void stringNode() throws IOException { 30 String str = "天王蓋地虎\n" 31 + "寶塔鎮河妖\n"; 32 char[] buf = new char[32]; 33 int hasRead = 0; 34 //StringReader將以String字符串爲節點讀取數據 35 try (StringReader sr = new StringReader(str)) { 36 while ((hasRead = sr.read(buf)) > 0) { 37 System.out.print(new String(buf, 0, hasRead)); 38 } 39 } catch (IOException e) { 40 e.printStackTrace(); 41 } 42 43 //因爲String是一個不可變類,所以建立StringWriter時,其實是以一個StringBuffer做爲輸出節點 44 try (StringWriter sw = new StringWriter()) { 45 sw.write("黑夜給了我黑色的眼睛\n"); 46 sw.write("我卻用它尋找光明\n"); 47 //toString()返回sw節點內的數據 48 System.out.println(sw.toString()); 49 } catch (IOException e) { 50 e.printStackTrace(); 51 } 52 } 53 54 public static void keyIn() throws IOException { 55 try ( 56 //InputStreamReader是從byte轉成char的橋樑 57 InputStreamReader reader = new InputStreamReader(System.in); 58 //BufferedReader(Reader in)是char類型輸入的包裝類 59 BufferedReader br = new BufferedReader(reader); 60 ) { 61 String line = null; 62 while ((line = br.readLine()) != null) { 63 if (line.equals("exit")) { 64 //System.exit(1); 65 break; 66 } 67 System.out.println(line); 68 } 69 } catch (IOException e) { 70 e.printStackTrace(); 71 } 72 } 73 74 public static void pushback() throws FileNotFoundException, IOException { 75 try (PushbackReader pr = new PushbackReader(new FileReader("C:/PROJECT/JavaBasic/PROJECT_JavaBasic/src/io/TestIO.java"),64)) { 76 char[] buf = new char[32]; 77 String lastContent = ""; 78 int hasRead = 0; 79 while ((hasRead = pr.read(buf)) > 0) { 80 String content = new String(buf, 0, hasRead); 81 int targetIndex = 0; 82 if ((targetIndex = (lastContent + content).indexOf("targetIndex = (lastContent + content)")) > 0) { 83 pr.unread((lastContent + content).toCharArray()); 84 if (targetIndex > 32) { 85 buf = new char[targetIndex]; 86 } 87 pr.read(buf , 0 , targetIndex); 88 System.out.println(new String(buf, 0 , targetIndex)); 89 System.exit(0); 90 } else { 91 System.out.println(lastContent); 92 lastContent = content; 93 } 94 } 95 } catch (IOException e) { 96 e.printStackTrace(); 97 } 98 } 99 100 public static void main(String[] args) throws IOException { 101 printStream(); 102 //stringNode(); 103 //keyIn(); 104 //pushback(); 105 } 106 }
總結上面幾種流的應用場景: