Java IO 之 InputStream源碼

Writer      :BYSocket(泥沙磚瓦漿木匠) java

微         博:BYSocket git

豆         瓣:BYSocket github

FaceBook:BYSocket 數組

Twitter    :BYSocket 緩存

1、InputStream

InputStream是一個抽象類,即表示全部字節輸入流實現類的基類。它的做用就是抽象地表示全部從不一樣數據源產生輸入的類,例如常見的FileInputStream、FilterInputStream等。那些數據源呢?好比: 多線程

1) 字節數組(不表明String類,但能夠轉換) 分佈式

2) String對象 學習

3) 文件 測試

4) 一個其餘種類的流組成的序列化 (在分佈式系統中常見) spa

5) 管道(多線程環境中的數據源)

等等

兩者,注意它是屬於字節流部分,而不是字符流(java.io中Reader\Writer,下面會講到)。

FilterInputStream是爲各類InputStream實現類提供的「裝飾器模式」的基類。所以,能夠分爲原始的字節流和「裝飾」過的功能封裝字節流。

2、細解InputStream源碼的核心

源碼以下:

/**
 * 全部字節輸入流實現類的基類
 */
publicabstractclassSInputStream {
 
    // 緩存區字節數組最大值
    privatestaticfinalintMAX_SKIP_BUFFER_SIZE = 2048;
 
    // 從輸入流中讀取數據的下一個字節,以int返回
    publicabstractintread() throwsIOException;
 
    // 從輸入流中讀取數據的必定數量字節,並存儲在緩存數組b
    publicintread(byteb[]) throwsIOException {
        returnread(b, 0, b.length);
    }
 
    // 從輸入流中讀取數據最多len個字節,並存儲在緩存數組b
    publicintread(byteb[], intoff, intlen) throwsIOException {
        if(b == null) {
            thrownewNullPointerException();
        } elseif(off < 0|| len < 0|| len > b.length - off) {
            thrownewIndexOutOfBoundsException();
        } elseif(len == 0) {
            return0;
        }
 
        intc = read();
        if(c == -1) {
            return-1;
        }
        b[off] = (byte)c;
 
        inti = 1;
        try{
            for(; i < len ; i++) {
                c = read();
                if(c == -1) {
                    break;
                }
                b[off + i] = (byte)c;
            }
        } catch(IOException ee) {
        }
        returni;
    }
 
    // 跳過輸入流中數據的n個字節
    publiclongskip(longn) throwsIOException {
 
        longremaining = n;
        intnr;
 
        if(n <= 0) {
            return0;
        }
 
        intsize = (int)Math.min(MAX_SKIP_BUFFER_SIZE, remaining);
        byte[] skipBuffer = newbyte[size];
        while(remaining > 0) {
            nr = read(skipBuffer, 0, (int)Math.min(size, remaining));
            if(nr < 0) {
                break;
            }
            remaining -= nr;
        }
 
        returnn - remaining;
    }
 
    // 返回下一個方法調用能不受阻塞地今後讀取(或者跳過)的估計字節數
    publicintavailable() throwsIOException {
        return0;
    }
 
    // 關閉此輸入流,並釋放與其關聯的全部資源
 
    publicvoidclose() throwsIOException {}
 
    // 在此輸出流中標記當前位置
    publicsynchronizedvoidmark(intreadlimit) {}
 
    // 將此流從新定位到最後一次對此輸入流調用 mark 方法時的位置。
    publicsynchronizedvoidreset() throwsIOException {
        thrownewIOException("mark/reset not supported");
    }
 
    // 測試此輸入流是否支持 mark 和 reset 方法
    publicbooleanmarkSupported() {
        returnfalse;
    }
 
}




其中,InputStream下面三個read方法纔是核心方法:

public abstract int read()


抽象方法,沒有具體實現。由於子類必須實現此方法的一個實現。這就是輸入流的關鍵方法。

兩者,可見下面兩個read()方法都調用了這個方法子類的實現來完成功能的。


public int read(byteb[])


該方法是表示從輸入流中讀取數據的必定數量字節,並存儲在緩存字節數組b。其效果等同於調用了下面方法的實現:

read(b, 0, b.length)


若是b的長度爲 0,則不讀取任何字節並返回 0;不然,嘗試讀取至少 1 字節。若是由於流位於文件末尾而沒有可用的字節,則返回值 -1;不然,至少讀取一個字節並將其存儲在 b 中。

思考:這時候,怪不得不少時候, b != –1 或者 b != EOF


public int read(byteb[], intoff, intlen)


在輸入數據可用、檢測到流末尾或者拋出異常前,此方法一直阻塞。


該方法先進行校驗,而後校驗下個字節是否爲空。若是校驗經過後,
以下代碼:

int i = 1;
try{
    for(; i < len ; i++) {
        c = read();
        if(c == -1) {
            break;
        }
        b[off + i] = (byte)c;
    }
} catch(IOException ee) {
}


將讀取的第一個字節存儲在元素 b[off] 中,下一個存儲在 b[off+1] 中,依次類推。讀取的字節數最多等於 len。設 k 爲實際讀取的字節數;這些字節將存儲在 b[off] 到 b[off+k-1] 的元素中,不影響 b[off+k] 到 b[off+len-1] 的元素。

由於有上面兩個read的實現,因此這裏InputStream設計爲抽象類。 

3、小結

1. InputSream 對應着 OutputStream

2. 看源碼是享受人家寫代碼中流露的How

3. 泥瓦匠學習的代碼都在github上(同步osc git),歡迎你們點star,提意見,一塊兒進步。地址:https://github.com/JeffLi1993

相關文章
相關標籤/搜索