InputStream:字節輸入流的所有類的父類
OutputStream:字節輸出流的所有類的父類
這裏的輸入和輸出是針對內存說的,一般來說,向內存讀入數據爲輸入,從內存讀出爲輸出。
下邊是對兩個類的源碼分析:
InputStream.java
package java.io;
/**
* 字節輸入流的所有類的超類
* 1. Closeable:實現close方法,可以在try-with-resource中自動關閉資源
*/
public abstract class InputStream implements Closeable {
// 在skip方法中使用
private static final int MAX_SKIP_BUFFER_SIZE = 2048;
/**
* 1. 讀取輸入流數據的下一個字節,返回這個字節的int值,一個字節能表示的大小爲0-255,
* 所以這個方法的(正確)返回值範圍是0-255。
* 2. 如果該輸入流到達末尾處,沒有可用的字節來讀取,那麼返回-1。
* 3. 該方法會阻塞,直到 1)有輸入數據可用 2)到達流的末尾 3)有異常拋出。
* 4. 子類必須實現該方法
*/
public abstract int read() throws IOException;
/**
* 1. 讀取輸入流中若干(不是一個了,效率提升)字節並且將它們存儲在緩衝數組中,返回實際讀到的字節數量。
* 2. 該方法同樣會阻塞,直到 1)有輸入數據可用 2)到達流的末尾 3)有異常拋出。
* 3. 如果緩衝數組的長度爲0,那麼返回0;否則至少讀取一個字節。
* 如果讀到流的末尾,返回讀取的字節數。
* 4. 第一個讀取的字節存儲在b[0],下一個存儲在b[1],依次類推。讀取到的字節數量最多等於b數組的長度。假設
* k是實際讀取到的字節數量,這些字節將被存儲到b[0]-b[k-1]中,b[k]-b[b.length-1]的元素不受影響。這裏
* 的不受影響是什麼意思呢??
*/
public int read(byte b[]) throws IOException {
return read(b, 0, b.length);
}
/**
* 1. 從輸入流中讀取len個字節到字節數組中,儘可能的讀取len個字節,但是可能少於len個字節。返回實際讀取到的字節數。
* 如果len=0,那麼沒有數據可讀,返回0。
* 2. 第一個讀取的字節存儲在b[off]中,依次類推。最多讀len個字節。
*/
public int read(byte b[], int off, int len) throws IOException {
// 如果緩衝數組爲null,則拋出 NullPointerException
if (b == null) {
throw new NullPointerException();
} else if (off < 0 || len < 0 || len > b.length - off) {
// 1. 如果數組存儲數據的開始位置小於0,IndexOutOfBoundsException
// 2. 如果設置的讀取字節長度小於0,IndexOutOfBoundsException
// 3. 如果數組偏移後的剩餘長度不足len,IndexOutOfBoundsException
throw new IndexOutOfBoundsException();
} else if (len == 0) {
// 如果len=0,返回0,什麼也不做
return 0;
}
int c = read();
// 如果讀到的字節爲-1,說明到達流的末尾,返回-1
if (c == -1) {
return -1;
}
// 將讀取的第一個字節存入b[off]
b[off] = (byte)c;
// i表示讀取到的字節數
int i = 1;
try {
for (; i < len ; i++) {
c = read();
// 讀到流末尾處,終止循環
if (c == -1) {
break;
}
b[off + i] = (byte)c;
}
} catch (IOException ee) {
}
return i;
}
// n 表示傳入需要跳過的字節數
// 返回實際跳過的字節數
// 1. 當輸入流的數據大於n時,且 n<MAX_SKIP_BUFFER_SIZE時,則一次就可跳過n
// 2. 當輸入流的數據大於n時,且 n>MAX_SKIP_BUFFER_SIZE時,則一次只能讀取MAX_SKIP_BUFFER_SIZE個,最後一次讀取
// n%MAX_SKIP_BUFFER_SIZE個
// 3. 當輸入流的數據小於n時,且 n<MAX_SKIP_BUFFER_SIZE時,則一次就可跳過整個輸入流,不是n
// 還有其它場景,原理大致一樣
public long skip(long n) throws IOException {
// 記錄每循環一次讀取,剩餘需要跳過的字節數
long remaining = n;
// 記錄每次循環跳過的字節數
int nr;
// n 需要大於0,否則沒有意義
if (n <= 0) {
return 0;
}
int size = (int)Math.min(MAX_SKIP_BUFFER_SIZE, remaining);
byte[] skipBuffer = new byte[size];
while (remaining > 0) {
nr = read(skipBuffer, 0, (int)Math.min(size, remaining));
if (nr < 0) {
break;
}
remaining -= nr;
}
// 返回實際跳過的字節數,其實nr纔是統計每次跳過的字節數的變量,原理是 remianing(最終的) = remaining(其實就是n)-(nr1+nr2+nr3+...),
// 返回 n-remianing = nr1+nr2+nr3+...
return n - remaining;
}
public int available() throws IOException {
return 0;
}
public void close() throws IOException {}
/**
* mark和reset方法一起使用,mark表示標記某個reset恢復的位置
*/
public synchronized void mark(int readlimit) {}
public synchronized void reset() throws IOException {
throw new IOException("mark/reset not supported");
}
/*
* 是否支持mark和reset方法
*/
public boolean markSupported() {
return false;
}
}
OutputStream.java
package java.io;
/**
* 字節輸出流的超類,接收字節並將其發送到某個接收器
* 實現兩個重要的接口:
* 1. Closeable:實現close方法,可以在try-with-resource中自動關閉資源
* 2. Flushable:實現flush方法,可以操作底層刷新流
*/
public abstract class OutputStream implements Closeable, Flushable {
/*
* 子類必須實現的方法
*/
public abstract void write(int b) throws IOException;
public void write(byte b[]) throws IOException {
write(b, 0, b.length);
}
public void write(byte b[], int off, int len) throws IOException {
if (b == null) {
throw new NullPointerException();
} else if ((off < 0) || (off > b.length) || (len < 0) ||
((off + len) > b.length) || ((off + len) < 0)) {
throw new IndexOutOfBoundsException();
} else if (len == 0) {
return;
}
for (int i = 0 ; i < len ; i++) {
write(b[off + i]);
}
}
public void flush() throws IOException {
}
public void close() throws IOException {
}
}