5.IO流系統詳解

Java 流在處理上分爲字符流和字節流。字符流處理的單元爲 2 個字節的 Unicode 字符,分別操作字符、字符數組或字符串,而字節流處理單元爲 1 個字節,操作字節和字節數組。

Java 內用 Unicode 編碼存儲字符,字符流處理類負責將外部的其他編碼的字符流和 java 內 Unicode 字符流之間的轉換。而類 InputStreamReader 和 OutputStreamWriter 處理字符流和字節流的轉換。字符流(一次可以處理一個緩衝區)一次操作比字節流(一次一個字節)效率高。 

 

(一)以字節爲導向的 Stream------InputStream/OutputStream

InputStream 和 OutputStream 是兩個 abstact 類,對於字節爲導向的 stream 都擴展這兩個基類;

1、 InputStream

 

 


基類InputStream:

構造方法:

InputStream() 創建一個輸入的stream流

方法:

available():返回stream中的可讀字節數,inputstream類中的這個方法始終返回的是0,這個方法需要子類去實現。

close():關閉stream方法,這個是每次在用完流之後必須調用的方法。

read():方法是讀取一個byte字節,但是返回的是int。

read(byte[]):一次性讀取內容到緩衝字節數組

read(byte[],int,int):從數據流中的哪個位置offset開始讀長度爲len的內容到緩衝字節數組

skip(long):從stream中跳過long類型參數個位置

以上的方法都是很簡單理解的,這裏就不寫代碼介紹了。

下面還有三個方法:

mark(int):用於標記stream的作用

markSupported():返回的是boolean類型,因爲不是所有的stream都可以調用mark方法的,這個方法就是用來判斷stream是否可以調用mark方法和reset方法

reset():這個方法和mark方法一起使用的,讓stream回到mark的位置。

上面說的可能抽象了點,下面就用代碼來解釋一下吧:

[java] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. package com.io.demo;  
  2.   
  3. import java.io.BufferedInputStream;  
  4. import java.io.BufferedOutputStream;  
  5. import java.io.File;  
  6. import java.io.FileInputStream;  
  7. import java.io.FileOutputStream;  
  8. import java.io.IOException;  
  9. import java.io.InputStream;  
  10. import java.io.OutputStream;  
  11.   
  12. public class InputStreamTest {  
  13.     public static void main(String[] args) throws IOException {  
  14.         writeToFile();  
  15.         readFromFile();  
  16.     }  
  17.   
  18.     private static void readFromFile() {  
  19.         InputStream inputStream = null;  
  20.         try {  
  21.             inputStream = new BufferedInputStream(new FileInputStream(new File("test.txt")));  
  22.             // 判斷該輸入流是否支持mark操作  
  23.             if (!inputStream.markSupported()) {  
  24.                 System.out.println("mark/reset not supported!");  
  25.                 return;  
  26.             }  
  27.             int ch;  
  28.             int count = 0;  
  29.             boolean marked = false;  
  30.             while ((ch = inputStream.read()) != -1) {  
  31.                 System.out.print("." + ch);  
  32.                 if ((ch == 4) && !marked) {  
  33.                     // 在4的地方標記位置  
  34.                     inputStream.mark(10);  
  35.                     marked = true;  
  36.                 }  
  37.                 if (ch == 8 && count < 2) {  
  38.                     // 重設位置到4  
  39.                     inputStream.reset();  
  40.                     count++;  
  41.                 }  
  42.             }  
  43.         } catch (Exception e) {  
  44.             e.printStackTrace();  
  45.         } finally {  
  46.             try {  
  47.                 inputStream.close();  
  48.             } catch (Exception e) {  
  49.                 e.printStackTrace();  
  50.             }  
  51.         }  
  52.     }  
  53.   
  54.     private static void writeToFile() {  
  55.         OutputStream output = null;  
  56.         try {  
  57.             output = new BufferedOutputStream(new FileOutputStream(new File("test.txt")));  
  58.             byte[] b = new byte[20];  
  59.             for (int i = 0; i < 20; i++)  
  60.                 b[i] = (byte) i;  
  61.             // 寫入從0到19的20個字節到文件中  
  62.             output.write(b);  
  63.         } catch (IOException e) {  
  64.             e.printStackTrace();  
  65.         } finally {  
  66.             try {  
  67.                 output.close();  
  68.             } catch (IOException e) {  
  69.                 e.printStackTrace();  
  70.             }  
  71.         }  
  72.     }  
  73. }  
輸出:.0.1.2.3.4.5.6.7.8.5.6.7.8.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19

從輸出可以看到,我們在ch==4的時候調用了mark方法進行標記了,當ch==8的時候我們調用了reset方法,就讓stream回到了我們標記的地方重新讀取。

上面的例子是在整個讀取stream的過程中操作的,下面來看一下當我們讀取完一個stream的時候再去調用reset方法的效果:

[java] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. public static void main(String[] args) throws Exception{  
  2.         BufferedInputStream bis = new BufferedInputStream(new ByteArrayInputStream("Hello World!".getBytes()));  
  3.         int bytes = -1;  
  4.         //這裏進行標記  
  5.         bis.mark(12);  
  6.         while((bytes=bis.read())!=-1){  
  7.             System.out.print(bytes+",");  
  8.         }  
  9.         System.out.println();  
  10.         //讓標籤有效,此時bis又回到了開始點  
  11.         bis.reset();  
  12.         while((bytes=bis.read())!=-1){  
  13.             System.out.print(bytes+".");  
  14.         }  
  15.     }  
輸出:

72,101,108,108,111,32,87,111,114,108,100,33,
72.101.108.108.111.32.87.111.114.108.100.33.

我們可以看到當我們在stream讀取完調用reset方法的話,stream就會回到開始點。

通過上面的例子我們可能知道了mark和reset方法的作用和好處:

如果想對一個stream進行多次操作的話,只要讀取一次就可以了,不需要多次讀取,比如:上面當讀取完stream之後,想再去從頭操作stream,只需要調用reset方法即可,如果沒有mark的話,我們就需要從新在去讀取一次數據了。

下面再來看一下mark這個方法中的參數的意義:

根據JAVA官方文檔的描述,mark(int readlimit)方法表示,標記當前位置,並保證在mark以後最多可以讀取readlimit字節數據,mark標記仍有效。如果在mark後讀取超過readlimit字節數據,mark標記就會失效,調用reset()方法會有異常。但實際的運行情況卻和JAVA文檔中的描述並不完全相符。 有時候在BufferedInputStream類中調用mark(int readlimit)方法後,即使讀取超過readlimit字節的數據,mark標記仍有效,仍然能正確調用reset方法重置。

事實上,mark在JAVA中的實現是和緩衝區相關的。只要緩衝區夠大,mark後讀取的數據沒有超出緩衝區的大小,mark標記就不會失效。如果不夠大,mark後又讀取了大量的數據,導致緩衝區更新,原來標記的位置自然找不到了。

因此,mark後讀取多少字節才失效,並不完全由readlimit參數確定,也和BufferedInputStream類的緩衝區大小有關。  如果BufferedInputStream類的緩衝區大小大於readlimit,在mark以後只有讀取超過緩衝區大小的數據,mark標記纔會失效。

簡言之,BufferedInputStream類調用mark(int readlimit)方法後讀取多少字節標記才失效,是取readlimit和BufferedInputStream類的緩衝區大小兩者中的最大值,而並非完全由readlimit確定。這個在JAVA文檔中是沒有提到的。

看下面的例子Mark.java。


[java] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. package com.io.demo;  
  2.   
  3. import java.io.BufferedInputStream;  
  4. import java.io.ByteArrayInputStream;  
  5. import java.io.IOException;  
  6.      
  7. /**   
  8.  * @author WuDian   
  9.  *    
  10.  */     
  11. public class Mark {      
  12.     public static void main(String[] args) {      
  13.      
  14.         try {      
  15.             // 初始化一個字節數組,內有5個字節的數據      
  16.             byte[] bytes={1,2,3,4,5};      
  17.             // 用一個ByteArrayInputStream來讀取這個字節數組      
  18.             ByteArrayInputStream in=new ByteArrayInputStream(bytes);      
  19.             // 將ByteArrayInputStream包含在一個BufferedInputStream,並初始化緩衝區大小爲2。      
  20.             BufferedInputStream bis=new BufferedInputStream(in,2);       
  21.             // 讀取字節1      
  22.             System.out.print(bis.read()+",");      
  23.             // 在字節2處做標記,同時設置readlimit參數爲1      
  24.             // 根據JAVA文檔mark以後最多隻能讀取1個字節,否則mark標記失效,但實際運行結果不是這樣      
  25.             System.out.println("mark");      
  26.             bis.mark(1);      
  27.                   
  28.             /*   
  29.              * 連續讀取兩個字節,超過了readlimit的大小,mark標記仍有效   
  30.              */     
  31.             // 連續讀取兩個字節      
  32.             System.out.print(bis.read()+",");       
  33.             System.out.print(bis.read()+",");       
  34.             // 調用reset方法,未發生異常,說明mark標記仍有效。      
  35.             // 因爲,雖然readlimit參數爲1,但是這個BufferedInputStream類的緩衝區大小爲2,      
  36.             // 所以允許讀取2字節      
  37.             System.out.println("reset");      
  38.             bis.reset();      
  39.                   
  40.             /*   
  41.              * 連續讀取3個字節,超過了緩衝區大小,mark標記失效。   
  42.              * 在這個例子中BufferedInputStream類的緩衝區大小大於readlimit,   
  43.              * mark標記由緩衝區大小決定   
  44.              */     
  45.             // reset重置後連續讀取3個字節,超過了BufferedInputStream類的緩衝區大小      
  46.             System.out.print(bis.read()+",");      
  47.             System.out.print(bis.read()+",");      
  48.             System.out.print(bis.read()+",");      
  49.             // 再次調用reset重置,拋出異常,說明mark後讀取3個字節,mark標記失效      
  50.             System.out.println("reset again");      
  51.             bis.reset();      
  52.         } catch (IOException e) {      
  53.             // TODO Auto-generated catch block      
  54.             e.printStackTrace();      
  55.         }      
  56.     }      
  57. }      
運行結果:

1,mark
2,3,reset
2,3,4,reset again
java.io.IOException: Resetting to invalid mark
at java.io.BufferedInputStream.reset(Unknown Source)
at com.io.demo.Mark.main(Mark.java:51)

這樣我們就對上面的三個方法進行的解釋了。其實等說完所以的stream之後我們會發現,mark和reset方法只有Buffered類的stream有效,所以stream中都會有一個markSupported方法來判斷一個stream中的mark和reset方法是否可用。


上面就介紹了InputStream基類中的所有方法,下面是其的子類,對於子類可能會添加以下屬於自己特定的方法,我們這裏就只介紹這些特定的方法

1.1 ByteArrayInputStream -- 把內存中的一個緩衝區作爲 InputStream 使用 .

construct---

(A)ByteArrayInputStream(byte[]) 創建一個新字節數組輸入流( ByteArrayInputStream ),它從指定字節數組中讀取數據( 使用 byte 作爲其緩衝區數組)

(B)ByteArrayInputStream(byte[], int, int) 創建一個新字節數組輸入流,它從指定字節數組中讀取數據。

method---

方法都是實現了InputStream方法。


1.2 StringBufferInputStream -- 把一個 String 對象作爲 InputStream .

construct---  

StringBufferInputStream(String) 據指定串創建一個讀取數據的輸入流串。

method---

實現了InputStream中的部分方法

註釋:不推薦使用 StringBufferInputStream 方法。 此類不能將字符正確的轉換爲字節。

同 JDK 1.1 版中的類似,從一個串創建一個流的最佳方法是採用 StringReader 類。


1.3 FileInputStream -- 把一個文件作爲 InputStream ,實現對文件的讀取操作

construct---

(A)FileInputStream(File name) 創建一個輸入文件流,從指定的 File 對象讀取數據。

(B)FileInputStream(FileDescriptor) 創建一個輸入文件流,從指定的文件描述器讀取數據。

(C)-FileInputStream(String  name) 創建一個輸入文件流,從指定名稱的文件讀取數據。

method ---- 

實現了InputStream中的部分方法;

額外的兩個方法:

getChannel():這個方法返回一個FileChannel對象,這個主要用於JNIO中的通道的。

getFD():這個方法返回一個FileDescriptor對象,這個在構造函數中使用過。


1.4 PipedInputStream :實現了 pipe 的概念,主要在線程中使用 . 管道輸入流是指一個通訊管道的接收端。

一個線程通過管道輸出流發送數據,而另一個線程通過管道輸入流讀取數據,這樣可實現兩個線程間的通訊。

construct---

PipedInputStream() 創建一個管道輸入流,它還未與一個管道輸出流連接。

PipedInputStream(PipedOutputStream) 創建一個管道輸入流 , 它已連接到一個管道輸出流。

method---

實現了InputStream中的部分方法

額外的方法:

connection(PipedOutputStream):用來連接PipedOutputStream對象


1.5 SequenceInputStream :把多個 InputStream 合併爲一個 InputStream . “序列輸入流”類允許應用程序把幾個輸入流連續地合併起來,

並且使它們像單個輸入流一樣出現。每個輸入流依次被讀取,直到到達該流的末尾。

然後“序列輸入流”類關閉這個流並自動地切換到下一個輸入流。

construct---

SequenceInputStream(Enumeration) 創建一個新的序列輸入流,並用指定的輸入流的枚舉值初始化它。

SequenceInputStream(InputStream, InputStream) 創建一個新的序列輸入流,初始化爲首先 讀輸入流 s1, 然後讀輸入流 s2 。

method---

實現了InputStream中的部分方法。

[java] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. public class TestSequence {    
  2.   public static void main(String[] args)throws Exception{    
  3.   //不管怎麼樣,先創建兩個文件。從裏面讀取數據,(我的文件裏面有內容!)    
  4.   InputStream in1=new FileInputStream(new File("d:\\jack.txt"));    
  5.   InputStream in2=new FileInputStream(new File("d:\\jack2.txt"));    
  6.   //讀取,數據後要生成的文件    
  7.   OutputStream ou=new FileOutputStream(new File("d:\\jack3.txt"));    
  8.   //創建SequenceInputStream類,    
  9.   SequenceInputStream si=new SequenceInputStream(in1,in2);    
  10.   //因爲SequenceInputStream,是一個字節一個字節讀,要判斷一下是否讀完了。    
  11.   int c=0;    
  12.   while((c=si.read())!=-1){    
  13.   //這裏也是一個字節一個字節寫的。    
  14.   ou.write(c);    
  15.   }    
  16.   //關閉所有的資源    
  17.   si.close();    
  18.   ou.close();    
  19.   in2.close();    
  20.   in1.close();    
  21.   }    
  22.   }   
能夠將多個stream進行連接,然後輸出。

1.6 ObjectInputStream:用於操作Object的stream,這個在stream主要用在對象傳輸的過程中,其中牽涉到了序列化的知識

construct---

ObjectInputStream():實例化一個ObjectInputStream對象

ObjectInputStream(InputStream):使用一個InputStream對象來實例化一個ObjectInputStream對象,其中InputStream就是對象的輸入流

method---

實現了InputStream中的部分方法;

它自己有很多的額外的方法:

這裏就只介紹一下readObject(Object)方法,就是將一個對象寫入到stream中,但是這個object必須序列化

其他的還有像readInt,readFloat等這樣基本類型的方法,因爲基本類型對應的對象也都是Object.


1.7 FilterInputStream:是一個過濾的InputStream

constructor---

FilterInputStream(InputStream):使用一個InputStream爲參數實例化一個FilterInputStream,其實就是來修飾InputStream的

method---

實現了InputStream中的所有方法

他其實沒有作用,他的衆多子類是很有用的:

1.7.1 BufferedInputStream:使用緩衝區的stream

constructor---

BufferedInputStream(InputStream):使用InputStream爲參數初始化實例

BufferedInputStream(InputStream,int):能夠設置緩衝區大小的BufferedInputStream

method---

實現了FilterInputStream中的所有方法(其實也是實現了InputStream中的所有方法)


1.7.2 DataInputStream:數字格式化的stream

constructor---

DataInputStream(InputStream):使用InputStream參數來初始化實例

method---

實現了FilterInputStream中的部分方法

額外的方法:

readInt,readFloat,readDouble...這樣可以直接從stream中讀取基本類型的數據

還有其他的類就不做解釋了,因爲用到的很少了,有的可能一輩子都用不到


2、 OutputSteam

 

 


基類OutputStream

constructor---

OutputStream()

method---

write(int):寫入一個字節到stream中

write(byte[])寫入一個byte數組到stream中

write(byte[],int,int):把byte數組中從offset開始處寫入長度爲len的數據

close():關閉流,這個是在操作完stream之後必須要調用的方法

flush():這個方法是用來刷新stream中的數據,讓緩衝區中的數據強制的輸出


2.1 ByteArrayOutputStream : 把信息存入內存中的一個緩衝區中 . 該類實現一個以字節數組形式寫入數據的輸出流。

當數據寫入緩衝區時,它自動擴大。用 toByteArray() 和 toString() 能檢索數據。

constructor---

(A)--- ByteArrayOutputStream() 創建一個新的字節數組輸出流。

(B)--- ByteArrayOutputStream() 創建一個新的字節數組輸出流。

(C)--- ByteArrayOutputStream(int) 創建一個新的字節數組輸出流,並帶有指定大小字節的緩衝區容量。

method---

實現了OutputStream的部分方法:

額外的方法:

toByteArray() 將字節流轉化成一個字節數組,用於數據的檢索

toString() 將字節流轉化成一個String對象,默認採用系統的編碼轉化,同樣可以用於數據的檢索

toString(String) 根據指定字符編碼將緩衝區內容轉換爲字符串,並將字節轉換爲字符。

writeTo(OutputStream) 用 out.write(buf, 0, count) 調用輸出流的寫方法將該字節數組輸出流的全部內容寫入指定的輸出流參數。


2.2  FileOutputStream: 文件輸出流是向 File 或 FileDescriptor 輸出數據的一個輸出流。

constructor---

(A)FileOutputStream(File  name) 創建一個文件輸出流,向指定的 File 對象輸出數據。

(B)FileOutputStream(FileDescriptor) 創建一個文件輸出流,向指定的文件描述器輸出數據。

(C)FileOutputStream(String  name) 創建一個文件輸出流,向指定名稱的文件輸出數據。

(D)FileOutputStream(String, boolean) 用指定系統的文件名,創建一個輸出文件。

method---

實現了OutputStream中的部分方法。

額外的兩個方法:

getChannel():這個方法返回一個FileChannel對象,這個主要用於JNIO中的通道的。

getFD():這個方法返回一個FileDescriptor對象,這個在構造函數中使用過。


2.3 PipedOutputStream: 管道輸出流是指一個通訊管道的發送端。 一個線程通過管道輸出流發送數據,

而另一個線程通過管道輸入流讀取數據,這樣可實現兩個線程間的通訊。

constructor---

(A)PipedOutputStream() 創建一個管道輸出流,它還未與一個管道輸入流連接。

(B)PipedOutputStream(PipedInputStream) 創建一個管道輸出流,它已連接到一個管道輸入流。

method---

實現了OutputStream的部分方法

額外的方法:

connection(PipedInputStream):連接一個PipedInputStream方法

下面來看一下PipedInputStream和PipedOutputStream的例子:

[java] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. package com.io.demo;  
  2.   
  3. import java.io.BufferedInputStream;  
  4. import java.io.BufferedReader;  
  5. import java.io.ByteArrayInputStream;  
  6. import java.io.IOException;  
  7. import java.io.InputStreamReader;  
  8. import java.io.PipedInputStream;  
  9. import java.io.PipedOutputStream;  
  10.   
  11. public class IO {  
  12.       
  13.     public static void main(String[] args) throws Exception{  
  14.           
  15.         PipedOutputStream pos = new PipedOutputStream();  
  16.         try {  
  17.             PipedInputStream pis = new PipedInputStream(pos);  
  18.             new Thread(new InputStreamRunnable(pis)).start();  
  19.             new Thread(new OutputStreamRunnable(pos)).start();  
  20.         } catch (IOException e) {  
  21.             e.printStackTrace();  
  22.         }  
  23.     }  
  24.       
  25.     static class InputStreamRunnable implements Runnable{  
  26.         private PipedInputStream pis = null;  
  27.         public InputStreamRunnable(PipedInputStream pis){  
  28.             this.pis = pis;  
  29.         }  
  30.         @Override  
  31.         public void run() {  
  32.             BufferedReader sr = new BufferedReader(new InputStreamReader(pis));  
  33.             try {  
  34.                 System.out.println("讀取到的內容:"+sr.readLine());  
  35.                 sr.close();  
  36.             } catch (IOException e) {  
  37.                 e.printStackTrace();  
  38.             }  
  39.         }  
  40.           
  41.     }  
  42.       
  43.     static class OutputStreamRunnable implements Runnable{  
  44.         private PipedOutputStream pos = null;  
  45.         public OutputStreamRunnable(PipedOutputStream pos){  
  46.             this.pos = pos;  
  47.         }  
  48.         @Override  
  49.         public void run(){  
  50.             try {  
  51.                 pos.write("Hello World!".getBytes());  
  52.                 pos.close();  
  53.             } catch (IOException e) {  
  54.                 e.printStackTrace();  
  55.             }  
  56.         }  
  57.     }  
  58.   
  59. }  
其實PipedInputStream/PipedOutputStream相當於消費者和生產者機制。


2.4 ObjectOutputStream:輸出Object對象的stream

constructor---

ObjectOutputStream:實例化一個ObjectOutputStream對象

ObjectOutputStream(OutputStream):使用OutputStream對象來實例化一個ObjectOutputStream對象,將對象寫入到OutputStream中

method---

實現了OutputStream中的部分方法

額外的方法:

這裏只介紹一個writeObject(Object):將一個對象Object寫入到OutputStream中

同時他也有writeInt,writeFloat..這樣的基本類型的方法,因爲基本類型對應的對象類型都是Object的子類

關於ObjectInputStream/ObjectOutputStream主要用與將一個對象Object寫入到本地或者是在網絡中進行傳輸的,所以這些對象需要進行序列化操作。


2.5  FilterOutputStream:過濾的OutputStream

constructor---

FilterOutputStream(OutputStream):使用OutputStream參數實例化FilterOutputStream

method---

實現了OutputStream的所有方法

和FilterInputStream一樣,他其實也沒有什麼用途,他的子類很有用的

2.5.1 BufferedOutputStream:帶有緩衝區的stream

constructor---

BufferedOutputStream(OutputStream):使用OutputStream參數初始化BufferedOutputStream類

BufferedOutputStream(OutputStream,int):在初始化實例的時候指定緩衝區的大小

method---

實現了FilterOutputStream中的部分方法


2.5.2 DataOutputStream:具有格式化的OutputStream

constructor---

DataOutputStream(OutputStream):使用OutputStream參數來初始化DataOutputStream實例

method---

實現了FilterOutputStream中的部分方法

writeInt,writeFloat,writeDouble....能夠給直接向stream中寫入基本類型的方法


2.5.3 PrintStream:直接輸出到控制檯中:我們最熟悉的就是System.out他就是一個PrintStream

constructor---

PrintStream(OutputStream):使用OutputStream參數來實例化PrintStream

method---

實現了FilterOutputStream中的部分方法

print()有多個重載的方法,8中基本類型和String類型,同時他還可以進行格式化輸出。

其他還有一些stream可能用不到,這裏就不做介紹了。


( 二 )以字符爲導向的 Stream  Reader/Writer

以 Unicode 字符爲導向的 stream ,表示以 Unicode 字符爲單位從 stream 中讀取或往 stream 中寫入信息。

Reader/Writer 爲 abstact 類

以 Unicode 字符爲導向的 stream 包括下面幾種類型:

1. Reader

 

 


Reader基類:基於字符流的stream

constructor--

Reader():無參的構造方法

method---

這些方法和InputStream中的方法是一一對應的,就是讀取的類型不同,InputStream中讀取的是byte,而Reader中讀取的是char


1.1 CharArrayReader :與 ByteArrayInputStream 對應此類實現一個可用作字符輸入流的字符緩衝區

constructor---

CharArrayReader(char[]) 用指定字符數組創建一個 CharArrayReader 。

CharArrayReader(char[], int, int) 用指定字符數組創建一個 CharArrayReader

method---

實現了部分Reader的方法


1.2 StringReader  與 StringBufferInputStream 對應其源爲一個字符串的字符流。


1.3 FileReader : 與 FileInputStream 對應


1.4 PipedReader :與 PipedInputStream 對應


1.5 InputStreamReader將InputStream轉化成Reader

 

2.  Writer

 

2.1    CharArrayWriter: 與 ByteArrayOutputStream 對應


2.2   StringWriter:無與之對應的以字節爲導向的 stream


2.3  FileWriter: 與 FileOutputStream 對應


2.4  PipedWriter:與 PipedOutputStream 對應


2.5 OutputStreamWriter:將OutputStream轉化成Writer


2.6 PrintReader和PrintStream對應

 

3、兩種不同導向的 Stream 之間的轉換  

3.1 InputStreamReader 和 OutputStreamReader :

把一個以字節爲導向的 stream 轉換成一個以字符爲導向的 stream 。

InputStreamReader 類是從字節流到字符流的橋樑:它讀入字節,並根據指定的編碼方式,將之轉換爲字符流。

使用的編碼方式可能由名稱指定,或平臺可接受的缺省編碼方式。

InputStreamReader 的 read() 方法之一的每次調用,可能促使從基本字節輸入流中讀取一個或多個字節。

爲了達到更高效率,考慮用 BufferedReader 封裝 InputStreamReader ,

BufferedReader in = new BufferedReader(new InputStreamReader(System.in));

例如: // 實現從鍵盤輸入一個整數

[java] view plaincopy
  1. String s = null;             
  2. InputStreamReader re = new InputStreamReader(System.in);  
  3.               BufferedReader br = new BufferedReader(re);  
  4.               try {  
  5.               s = br.readLine();  
  6.               System.out.println("s= " + Integer.parseInt(s));  
  7.               br.close();  
  8.               }  
  9.               catch (IOException e)  
  10.               {  
  11.               e.printStackTrace();  
  12.               }  
  13.               catch (NumberFormatException e)// 當應用程序試圖將字符串轉換成一種數值類型,但該字符串不能轉換爲適當格式時,拋出該異常。  
  14.               {  
  15.               System.out.println(" 輸入的不是數字 ");  
  16.               }  

InputStreamReader(InputStream) 用缺省的字符編碼方式,創建一個 InputStreamReader 

InputStreamReader(InputStream, String) 用已命名的字符編碼方式,創建一個 InputStreamReader 

OutputStreamWriter 將多個字符寫入到一個輸出流,根據指定的字符編碼將多個字符轉換爲字節。

每個 OutputStreamWriter 合併它自己的 CharToByteConverter, 因而是從字符流到字節流的橋樑。

 

(三)Java IO 的一般使用原則 :  

一、按數據來源(去向)分類:

1 、是文件: FileInputStream, FileOutputStream, ( 字節流 )FileReader, FileWriter( 字符 )

2 、是 byte[] : ByteArrayInputStream, ByteArrayOutputStream( 字節流 )

3 、是 Char[]: CharArrayReader, CharArrayWriter( 字符流 )

4 、是 String: StringBufferInputStream, StringBufferOuputStream ( 字節流 )StringReader, StringWriter( 字符流 )

5 、網絡數據流: InputStream, OutputStream,( 字節流 ) Reader, Writer( 字符流 )


二、按是否格式化輸出分:

1 、要格式化輸出: PrintStream, PrintWriter


三、按是否要緩衝分:

1 、要緩衝: BufferedInputStream, BufferedOutputStream,( 字節流 ) BufferedReader, BufferedWriter( 字符流 )


四、按數據格式分:

1 、二進制格式(只要不能確定是純文本的) : InputStream, OutputStream 及其所有帶 Stream 結束的子類

2 、純文本格式(含純英文與漢字或其他編碼方式); Reader, Writer 及其所有帶 Reader, Writer 的子類


五、按輸入輸出分:

1 、輸入: Reader, InputStream 類型的子類

2 、輸出: Writer, OutputStream 類型的子類


六、特殊需要:

1 、從 Stream 到 Reader,Writer 的轉換類: InputStreamReader, OutputStreamWriter

2 、對象輸入輸出: ObjectInputStream, ObjectOutputStream

3 、進程間通信: PipeInputStream, PipeOutputStream, PipeReader, PipeWriter

4 、合併輸入: SequenceInputStream

5 、更特殊的需要: PushbackInputStream, PushbackReader, LineNumberInputStream, LineNumberReader

決定使用哪個類以及它的構造進程的一般準則如下(不考慮特殊需要):

首先,考慮最原始的數據格式是什麼: 原則四

第二,是輸入還是輸出:原則五

第三,是否需要轉換流:原則六第 1 點

第四,數據來源(去向)是什麼:原則一

第五,是否要緩衝:原則三 (特別註明:一定要注意的是 readLine() 是否有定義,有什麼比 read, write 更特殊的輸入或輸出方法)


第六,是否要格式化輸出:原則二
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章