1. 程式人生 > >[Java開發之路](8)輸入流和輸出流

[Java開發之路](8)輸入流和輸出流



1. Java流的分類 按流向分: 輸入流: 可以從其中讀入一個位元組序列的物件稱作輸入流 輸出流: 可以向其中寫入一個位元組序列的物件稱作輸出流 這些位元組序列的來源地和目的地可以是檔案,而且通常都是檔案,但是也可以是網路連線,甚至是記憶體塊。抽象類InputStream和OutputStream構成了輸入和輸出類層結構的基礎。 按資料傳輸單位分: 位元組流: 以位元組為單位傳輸資料的流 字元流: 以字元為單位傳輸資料的流 按功能分: 節點流: 用於直接操作目標裝置的流 過濾流: 是對一個已存在的流的連結和封裝,通過對資料進行處理為程式提供功能強大、靈活的讀寫功能。 2. 讀寫位元組(
InputStream和OutputStream) (1)InputStream類有一個抽象方法: abstractint read() 這個方法將讀入一個位元組,並返回讀入的位元組,或者在遇到輸入源結尾時返回-1。在設計具體的輸入流時,必須覆蓋這個方法以提供適用的功能,例如,在FileInputStream類中,這個方法將從某個檔案中讀入一個位元組。 InputStream類還有若干個非抽象的方法,它們可以讀入一個位元組陣列,或者跳過大量的位元組。這些方法都要呼叫抽象的read方法,因此各個子類都只需覆蓋一個方法。 (2)OutputStream類定義了下面的抽象方法: abstract
void write(int b)
它可以向某個輸出位置寫出一個位元組。 (3)read和write方法在執行時都將阻塞直至位元組確實被讀入或寫出。這就意味著如果流不能被立即訪問(通常因為網路連線忙),那麼當前的執行緒將被阻塞。這使得在這兩個方法等待指定流變為可用的這段時間內,其他的執行緒就有機會去執行有用的工作。 當你完成對流的讀寫時,應該通過呼叫close方法來關閉它,這個呼叫會釋放掉十分有限的作業系統資源。如果一個應用程式打開了過多的流而沒有關閉,那麼系統資源將被耗盡。關閉一個輸出流的同時還會沖刷用於該輸出流的緩衝區所有被臨時置於緩衝區中,以便用更大的包的形式傳遞的字元在關閉輸出流時都將被送出
。如果不關閉檔案,那麼寫出的位元組的最後一個包可能將永遠也得不到傳遞。我們可以使用flush方法認為的沖刷這些輸出。 即使某個流類提供了使用原生的read和write功能的某些具體方法,應用系統的程式設計師還是很少使用它們,因為大家感興趣的資料可能包含數字,字串和物件,而不是原生位元組。 Java提供了眾多從基本InputStream和OutputStream類匯出的類,這些類使我們可以處理那些以常用格式表示的資料,而不只是位元組。 3.流家族 流家族中的成員按照它們的使用方法進行劃分,形成了處理位元組和字元的兩個單獨的層次結構。Java中字元是採用Unicode標準,一個字元是16位,即一個字元使用兩個位元組來表示。因此JAVA才引入字元流。 java.io包中包含了流式I/O所需要的所有類。在java.io包中有四個基本類:InputStream、OutputStream及Reader、Writer類,它們分別處理位元組流和字元流。
輸入/輸出 位元組流 字元流
輸入流 InputStream Reader
輸出流 OutputStream Writer
位元組方面:InputStream和OutputStream類讀寫單子個位元組或位元組陣列。要想讀寫字串和數字,就需要功能更強大的子類,例如,DataInputStream和DataOutputStream可以以二進位制格式讀寫所有的基本Java型別。 字元方面:對於Unicode文字,可以使用抽象類Reader和Writer的子類。Reader和Writer類的基本方法與InputStream和OutputStream中的方法類似。 4 位元組流InputStream和OutputStream
4.1 InputStream抽象類 InputStream 為位元組輸入流,它本身為一個抽象類,必須依靠其子類實現各種功能,此抽象類是表示位元組輸入流的所有類的超類。 繼承自InputStream  的流都是向程式中輸入資料的,且資料單位為位元組(8bit);
InputStream是輸入位元組資料用的類,所以InputStream類提供了3種過載的read方法。Inputstream類中的常用方法: 
常用方法 描述
public abstract int read( ) 從輸入流中讀取下一個位元組資料。返回位元組使用高位補0的int型別值表示(0-255),若返回值為-1說明沒有讀取到任何位元組,輸入流達到盡頭。
public int read(byte b[ ]) 從輸入流中讀取b.length個位元組的資料放到位元組陣列b中。返回值是讀取的位元組數。如果位元組陣列的長度為0,不會讀取任何位元組資料,返回0,否則至少嘗試去讀取一個位元組的資料。如果沒有獲取到位元組資料,表示流到達檔案末尾,返回-1。第一個讀取的位元組儲存在b[0],以此類推。
public int read(byte b[ ], int off, int len) 從輸入流中讀取至多len個位元組的資料放到位元組陣列b中。返回值是讀取的實際位元組數。如果位元組陣列的長度為0,不會讀取任何位元組資料,返回0,否則至少嘗試去讀取一個位元組的資料。如果沒有獲取到位元組資料,表示流到達檔案末尾,返回-1。第一個讀取的位元組儲存在b[off],下一個儲存在b[off+1],以此類推。
public int available( ) 返回輸入流中可以讀取的位元組數。注意:若輸入阻塞,當前執行緒將被掛起,如果InputStream物件呼叫這個方法的話,它只會返回0,這個方法必須由繼承InputStream類的子類物件呼叫才有用。注意:雖然很多InputStream的實現類可以正確的返回輸入流的總位元組數,但是並不是全都都可以。所以使用這個方法的返回值去分配位元組大小來容納輸入流的所有資料一定不是一個正確的方法。
public long skip(long n) 忽略輸入流中的n個位元組,返回值是實際忽略的位元組數, 如果為負數,表示沒有跳過任何位元組資料。
public int close( ) 關閉輸入流,釋放分配給輸入流的系統資源。
InputStream子類:
InputStream的作用是用來表示那些那些從不同資料來源產生輸入的類。這些資料來源包括:
  • 位元組陣列
  • String物件
  • 檔案
  • "管道",工作方式與實際管道相似,從一端進入,從一端輸出
  • 一個由其他種類的流組成的序列,以便我們可以將它們收集合併到一個流內
每一種資料來源都有相應的InputStream子類。另外,FilterInputStream也屬於一種InputStream,為"裝飾器"類提供基類,其中"裝飾器"類可以把屬性或有用的介面與輸入流連線在一起。
功能
ByteArrayInputStream 允許將記憶體中緩衝區當做InputStream使用
StringBufferInputStream 將String轉換成InputStream
FileInputStream 用於從檔案中讀取資訊
PipedInputStream 產生用於寫入相關PipedOutputStream的資料。實現“管道化”概念。
SequenceInputStream 將兩個或者多個InputStream物件轉換成單一InputStream
FilterInputStream 抽象類,作為“裝飾器”的介面。其中,“裝飾器”為其他的InputStream類提供有用的功能。
4.2 OutputSream抽象類 OutputStream提供了3個write方法來做資料的輸出,這個是和InputStream是相對應的。
常用方法 描述
public abstract void write(int b) 將指定位元組寫入到輸出流中。一般是將引數b的低八位(一個位元組)寫入到輸出流中。b的高八位被忽略掉。
public void write(byte[] b) 從位元組陣列b中向輸出流中寫入b.length個位元組資料。
public void write(byte[] b,int off,int len) 從位元組陣列b偏移位置為off的開始位置向輸出流寫入len個位元組資料。b[off]是第一個被寫入的位元組,b[off+len-1]是最後一個被寫入的位元組。如果b為null,會丟擲NullPointer異常;如果off或者len是負數,或者off+len比位元組陣列b的長度大,則會丟擲IndexOutOfBoundsException異常。
public void flush() 清空輸出流,並強制將所有緩衝的輸出位元組被寫出。
public void close() 關閉輸出流,釋放分配給輸出流的系統資源。
OutputStream的子類:
該類別的類決定了輸出所要去往的目標:位元組陣列(但不是String,不過你當然可以使用位元組陣列自己來建立),檔案或管道。
功能
ByteArrayOutputStream 在記憶體中建立緩衝區,所有送往“流”的資料都要放置在此緩衝區。
FileOutputStream 用於將資訊寫至檔案。
PipedOutputStream 任何寫入其中的資訊都會自動作為PipedInputStream的輸出。實現“管道化”概念。
FilterOutputStream 抽象類,作為“裝飾器”的介面。其中,“裝飾器”為其他的OutputStream類提供有用的功能。
5. 字元流 Reader和Writer 當我們初次看到Reader和Writer類時,可能會以為這是兩個用來代替InputStream和OutputStream的類,但實際上不是。儘管一些原始的“流”類庫不再使用(如果使用它們,則會收到編譯器的警告資訊),但是InputStream和OutputStream在以面向位元組流形式的IO時仍然可以提供有價值的功能。Reader和Writer則提供了相容Unicode與面向字元的I/O功能。有時候我們還會把來自"位元組"層次結構中的類和來自"字元"層次結構中類結合使用。為了實現這個目標,我們要用到"介面卡"(adapter)類:InputStreamReader可以把InputStream轉換為Reader,而OutputStream可以把OutputStream轉換為Writer。 設計Reader和Writer繼承層次結構是為了國際化。老的IO流繼承層次結構只能支援8位位元組流,並且不能很好的處理16位的Unicode字元。設計它的目的就是為了在所有的IO操作中都支援Unicode。 Reader的子類:
Writer的子類:
6. FileInputStream和FileOutputStream 6.1 FileInputStream
FileInputStream 從檔案系統中的某個檔案中獲得輸入位元組。

(1)構造方法
構造方法 描述
FileInputStream(String name) 使用由name字串指定路徑名檔案建立FileInputStream物件
FileInputStream(File file) 使用由file物件指定路徑名的檔案建立FileInputStream物件
// FileInputStream(String name)String path ="D:\\Recommended system.txt";FileInputStream stream =newFileInputStream(path);// FileInputStream(File file)File file =newFile(path);FileInputStream stream2 =newFileInputStream(file); (2)說明
  • 用於讀取諸如影象資料之類的原始位元組流。(要讀取字元流,請考慮使用 FileReader)
  • 包含其他一些輸入流,它將這些流用作其基本資料來源,它可以直接傳輸資料或提供一些額外的功能。
  • 類本身只是簡單地重寫那些將所有請求傳遞給所包含輸入流的 InputStream 的所有方法。
  • 其子類可進一步重寫這些方法中的一些方法,並且還可以提供一些額外的方法和欄位。
(3)例項 package com.qunar.io;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.IOException;publicclassIOUtil{publicstaticvoid main(String[] args){try{String path ="D:\\demo.txt";FileInputStream stream =newFileInputStream(path);int num =100;byte[] buff =newbyte[num];while((stream.read(buff,0,num))!=-1){System.out.println("NewLine->"+newString(buff));}//while stream.close();}catch(FileNotFoundException e){ e.printStackTrace();}catch(IOException e){ e.printStackTrace();}}} 執行結果:

NewLine->My father was a self-taught mandolin player. He was one of the best string instrument players in our NewLine-> town. He could not read music, but if he heard a tune a few times, he could play it. When he was yo NewLine->unger, he was a member of a small country music band. They would play at local dances and on a NewLine->ccasions would play for the local radio station. He often told us how he had auditioned and earned a NewLine-> position in a band that featured Patsy Cline as their lead singer. He told the family that after he NewLine-> was hired he never went back. Dad was a very religious man. He stated that there was a lot of drink NewLine->ing and cursing the day of his audition and he did not want to be around that type of environment.nk
6.2 FileOutputStream
(1)建構函式
建構函式 描述
FileOutputStream(String name) 使用由name字串指定路徑名的檔案建立一個新的檔案輸出流。
FileOutputStream(String name,boolean append) 使用由name字串指定路徑名的檔案建立一個新的檔案輸出流。如果append引數為true,那麼資料將被新增到檔案末尾,而具有相同名字的已有檔案不會被刪除(末尾新增資料);否則這個方法刪除所有具有相同名字的已有檔案。
FileOutputStream(File file) 使用由file物件指定路徑名的檔案建立一個新的檔案輸出流。
FileOutputStream(File file,boolean append) 使用由file物件指定路徑名的檔案建立一個新的檔案輸出流。如果append引數為true,那麼資料將被新增到檔案末尾,而具有相同名字的已有檔案不會被刪除(末尾新增資料);否則這個方法刪除所有具有相同名字的已有檔案。
(2)案例 package com.qunar.io;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;publicclassIOUtil{publicstaticvoid main(String[] args){try{String path ="D:\\from.txt";String path2 ="D:\\to.txt";FileInputStream inputStream =newFileInputStream(path);FileOutputStream outputStream =newFileOutputStream(path2);int num =100;byte[] buff =newbyte[num]; // 由檔案寫至記憶體while((inputStream.read(buff,0,num))!=-1){ // 由記憶體寫至檔案中 outputStream.write(buff);}//while inputStream.close(); outputStream.close();}catch(FileNotFoundException e){ e.printStackTrace();}catch(IOException e){ e.printStackTrace();<