InputStream(一)

首先了解對流的定義:
流分兩種,輸入流和輸出流:
輸入流:可以從其中讀入一個字節序列的對象稱作輸入流。
輸出流:可以向其中寫入一個字節序列的對象稱作輸出流。

字節序列的來源和目的地:文件、網絡連接、甚至是內存塊。

其次從結構圖中看整個IO流的一個大致的脈絡:

這裏寫圖片描述

從結構圖中可以看出整個IO流分爲兩大塊,字節流和字符流。

原因:面向字節的流不便於處理以Unicode形式存儲的信息(Unicode中每個字符都使用了多個字節來表示),所有從抽象類Reader和Writer中繼承出來了一個專門處理Unicode字符的單獨的類層次結構。這些類擁有的讀入和寫出操作都是基於兩個字節的Unicode碼元的,而不是基於單字節的字符。

而由於字符流是建立在字節流之上的,所以對於總體來說,InputStream和OutputStream構成了輸入/輸出(I/O)類層次結構的基礎。

所以之後得從InputStream的API中去了解是怎麼實現工作原理的,在這裏說一下,jdk版本爲1.7:

InputStream API:

這裏寫圖片描述

在這裏可以看出InputStream這個抽象類實現了Closeable這個接口。

追蹤到對原始的接口AutoCloseable接口裏去會發現這個接口中只有一個close()方法:

這裏寫圖片描述

在這裏我們預想的肯定是InputStream這個抽象類中實現了AutoCloseable接口中的close()方法,那麼回過頭來看InputStream這個抽象類:

這裏寫圖片描述

在InputStream這個抽象類中,我們只看到了這個模板方法,並沒有對AutoCloseable接口裏的close()方法做相應的處理,由此可見,close()方法必定由InputStream的子類去實現。

想到這,我們可以從結構圖中找一個InputStream中找一個子類來大致看一下close()是怎麼實現的,在這裏我找的是FileInputStream,下面來看一下對close()的處理:

這裏寫圖片描述
這裏寫圖片描述

在這裏不細說這段代碼處理的流程,因爲之後補充的時候有可能會提到,到時候細說,大致說一下close()方法的作用:

每當完成對流的讀寫時,應當通過close()方法來關閉,這個調用會釋放十分有限的操作系統資源,同時還會沖刷用於該輸入輸出流的緩存區,所有被置於緩存區中,以便於用更大的包的形式,傳遞的字符,在關閉輸入/輸出流時都將被送出。
如果不關閉文件,那麼寫出字節的最後一個包可能永遠也得不到傳遞。

手動:可以用flush()方法來人爲的沖刷這些輸出。

現在我們回到InputStream這個抽象類中,來看看裏面的方法到底有什麼作用。

讀寫字節:

這裏寫圖片描述

從對這個方法的註釋中,我們可以瞭解到read()這個抽象方法是從輸入流中讀取下一個字節的數據。字節的值作爲int範圍在0到返回255,如果沒有可以的字節(遇到輸入源結尾時)返回-1.

這個方法塊直到輸入數據是可用的,檢測到流的結束,或者拋出異常。
該方法的一個子類必須提供一個實現。

讀入一個字節數組:
這裏寫圖片描述

在這個方法中,傳入了一個byte類型的字節數組,之後再跳轉到有三個參數的read()中,我們在來看有三個參數的read()方法。

這裏寫圖片描述
這裏寫圖片描述

在這段代碼中,我們首先來看看三個參數的作用:
byte[] b:要被處理的一個字節序列
int off :第一個讀入字節應該被放置在b中的偏移量,默認是0
int len : 讀入字節的最大數量

在方法中新建了int類型的變量i,用來記錄讀入的字節數,並且在方法的最後返回。

所以綜上所述:

這裏寫圖片描述

這個方法是讀入一個數組,並且返回實際讀入的字節數,或者在碰到流的結尾時返回-1(read()方法中實現),但是這個方法最多讀入b.length個字節。

在輸入流中跳過n個字節:

這裏寫圖片描述

首先理解一下這段代碼做了什麼:

首先確定了讀取數組的大小,用Math.min這個方法來比較兩個參數的大小,並選取小的那個值作爲數組的大小,這裏解釋一下兩個參數:

MAX_SKIP_BUFFER_SIZE:用於確定最大緩存區大小,這裏確定值爲2048
remaining:傳入的參數的字節數大小

這裏可以理解爲當傳入跳過的字節數大於最大緩存區大小時截取傳入跳過的字節數,截取的大小爲最大緩存區大小。

之後用讀取數組的方式讀取,最後返回實際跳過的字節數(如果碰到流的結尾,則可能小於n)。

在不阻塞的情況下可獲取的字節數(阻塞意味着當前線程將失去它對資源的佔用)

這裏寫圖片描述

從對這個方法的註釋上我們可以知道,這個方法是被用來獲取不阻塞情況下讀入的字節數,並且這個方法是應該被子類所覆蓋的。

標記輸入流的位置:

這裏寫圖片描述

從對API的註釋解釋中可以知道這個方法的作用:
在輸入流的當前位置打了一個標記(並非所有的流都支持這個特性),如果從輸入流中已經讀入的字節對於readlimit,則這個流允許忽略這個標記。

重置讀入流:

這裏寫圖片描述

返回到最後一個標記,隨後對read的調用將重新讀入這些字節。如果當前沒有任何標記,則這個流不能被重置,同樣的這個類需要子類去實現。

判斷流是否允許打標記

這裏寫圖片描述

如果這個流支持打標記,則返回true,不過不支持,返回false。

總結:應用系統的程序員還是很少使用原來的read()和writer()方法,因爲大家感興趣的數據可能包含數字、字符串和對象,而不是原生字節。
所以Java提供了衆多從基本的InputStream和OutputStream導出的類,來處理以常用格式表示的數據。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章