JAVA基礎知識之IO——Java IO體系及經常使用類

Java IO體系

我的以爲能夠用「字節流操做類和字符流操做類組成了Java IO體系」來高度歸納Java IO體系。java

借用幾張網絡圖片來講明(圖片來自 http://blog.csdn.net/zhangerqing/article/details/8466532 )編程

  •  基於字節的IO操做

 

 

 
  •  基於字符的IO操做

 

 

 

 

 從上圖能夠看到,整個Java IO體系都是基於字符流(InputStream/OutputStream) 和 字節流(Reader/Writer)做爲基類,根據不一樣的數據載體或功能派生出來的。數組

IO經常使用類

  • 文件流:FileInputStream/FileOutputStream, FileReader/FileWriter

這四個類是專門操做文件流的,用法高度類似,區別在於前面兩個是操做字節流,後面兩個是操做字符流。它們都會直接操做文件流,直接與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/PrintWriter/Scanner

PrintStream能夠封裝(包裝)直接與文件交互的節點流對象OutputStream, 使得編程人員能夠忽略設備底層的差別,進行一致的IO操做。所以這種流也稱爲處理流或者包裝流。性能

PrintWriter除了能夠包裝字節流OutputStream以外,還能包裝字符流Writerspa

Scanner能夠包裝鍵盤輸入,方便地將鍵盤輸入的內容轉換成咱們想要的數據類型。.net

  • 字符串流:StringReader/StringWriter

這兩個操做的是專門操做String字符串的流,其中StringReader能從String中方便地讀取數據並保存到char數組,而StringWriter則將字符串類型的數據寫入到StringBuffer中(由於String不可寫)。code

  • 轉換流:InputStreamReader/OutputStreamReader

這兩個類能夠將字節流轉換成字符流,被稱爲字節流與字符流之間的橋樑。咱們常常在讀取鍵盤輸入(System.in)或網絡通訊的時候,須要使用這兩個類

  • 緩衝流:BufferedReader/BufferedWriter , BufferedInputStream/BufferedOutputStream

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 }

 

 

總結上面幾種流的應用場景:

  • FileInputStream/FileOutputStream  須要逐個字節處理原始二進制流的時候使用,效率低下
  • FileReader/FileWriter 須要組個字符處理的時候使用
  • StringReader/StringWriter 須要處理字符串的時候,能夠將字符串保存爲字符數組
  • PrintStream/PrintWriter 用來包裝FileOutputStream 對象,方便直接將String字符串寫入文件 
  • Scanner 用來包裝System.in流,很方便地將輸入的String字符串轉換成須要的數據類型
  • InputStreamReader/OutputStreamReader ,  字節和字符的轉換橋樑,在網絡通訊或者處理鍵盤輸入的時候用
  • BufferedReader/BufferedWriter , BufferedInputStream/BufferedOutputStream , 緩衝流用來包裝字節流後者字符流,提高IO性能,BufferedReader還能夠方便地讀取一行,簡化編程。
相關文章
相關標籤/搜索