一、說明
哈哈,這是學習Java之路的第一篇博文。雖然說接觸學習Java有一段時間了,但是對流的概念一直並不是很清楚。也看了很多資料,但是感覺還是非常的抽象很難去理解。但是流又是Java中很重要的一部分,所以就決定花點時間好好弄一下。這篇文章也並非全部是我的原創文章,我瀏覽了寫的比較好的博客,將其修改添加,加上一些自己的看法,就當成自己學習的筆記。僅供學習參考。參考原文鏈接
二、ByteArrayInputStream類
ByteArrayInputStream 是字節數組輸入流。它繼承於InputStream。
它包含一個內部緩沖區,該緩沖區包含從流中讀取的字節;通俗點說,它的內部緩沖區就是一個字節數組,而ByteArrayInputStream本質就是通過字節數組來實現的。
我們都知道,InputStream通過read()向外提供接口,供它們來讀取字節數據;而ByteArrayInputStream 的內部額外的定義了一個計數器,它被用來跟蹤 read() 方法要讀取的下一個字節。
InputStream類
InputStream類函數列表
函數 | 返回值 | 功能 |
public int read() throws IOEXception | 返回下一個數據字節 (返回 |
從輸入流中讀取數據的下一個字節 |
public int read(byte[] b) throws IOEXception | 以整數形式返回實際讀取的字節數。 如果因為已經到達流末尾而不再有數據可用, 則返回 |
從輸入流中讀取一定數量的字節, 並將其存儲在緩沖區數組 |
public int read(byte[] b,int off,int len) throws IOEXception |
讀入緩沖區的總字節數; 如果因為已到達流末尾而不再有數據可用, 則返回 |
將輸入流中最多 len 個數據字節讀入 byte 數 |
public long skip(long n) throws IOEXception | 跳過的實際字節數 | 跳過和丟棄此輸入流中數據的 n 個字 |
public int available() throws IOEXception |
可以不受阻塞地從此輸入流讀取 (或跳過)的估計字節數 |
返回此輸入流下一個方法調用 可以不受阻塞地從此輸入流讀取 (或跳過)的估計字節數 |
public boolean markSupported() | 如果此輸入流實例支持 mark 和 reset 方法, 則返回 |
測試此輸入流是否支持 mark 和 reset 方法 |
public void mark(int readlimit) | 無 | 在此輸入流中標記當前的位置 |
public void reset() throws IOEXception | 無 | 將此流重新定位到最后一次對此輸入流 調用 |
public void close() throws IOEXception | 無 | 關閉此輸入流並釋放與該流關聯的所有系統資源 |
關於上表的解釋:
1.可以這樣理解read()函數里的“讀取下一個字節”,就是光標在前
2.mark()方法的參數在實現中沒有什么實際的意義。
3.InputStream 的 close
方法不執行任何操作。
4.由於InputStream類是所以輸入流的父類,方法的實現也就沒有那么具體,它相當於給出了一個方法的規范,它的所以子類會按照這個規范去實現方法。也就是說,其子類方法的實現盡管不同,提供的功能卻是相同的。
5.想了解更加詳細的信息可以去查看jdk文檔,是學習java很重要的工具。jdk文檔
InputStream類源碼分析
由於上述給出了此類函數比較詳細的介紹,所以這里不作關於源碼太多的說明。

1 package java.io; 2 3 public abstract class InputStream implements Closeable { 4 5 // 能skip的大小 6 private static final int MAX_SKIP_BUFFER_SIZE = 2048; 7 8 // 從輸入流中讀取數據的下一個字節。 9 public abstract int read() throws IOException; 10 11 // 將數據從輸入流讀入 byte 數組。 12 public int read(byte b[]) throws IOException { 13 return read(b, 0, b.length); 14 } 15 16 // 將最多 len 個數據字節從此輸入流讀入 byte 數組。 17 public int read(byte b[], int off, int len) throws IOException { 18 if (b == null) { 19 throw new NullPointerException(); 20 } else if (off < 0 || len < 0 || len > b.length - off) { 21 throw new IndexOutOfBoundsException(); 22 } else if (len == 0) { 23 return 0; 24 } 25 26 int c = read(); 27 if (c == -1) { 28 return -1; 29 } 30 b[off] = (byte)c; 31 32 int i = 1; 33 try { 34 for (; i < len ; i++) { 35 c = read(); 36 if (c == -1) { 37 break; 38 } 39 b[off + i] = (byte)c; 40 } 41 } catch (IOException ee) { 42 } 43 return i; 44 } 45 46 // 跳過輸入流中的n個字節 47 public long skip(long n) throws IOException { 48 49 long remaining = n; 50 int nr; 51 52 if (n <= 0) { 53 return 0; 54 } 55 56 int size = (int)Math.min(MAX_SKIP_BUFFER_SIZE, remaining); 57 byte[] skipBuffer = new byte[size]; 58 while (remaining > 0) { 59 nr = read(skipBuffer, 0, (int)Math.min(size, remaining)); 60 if (nr < 0) { 61 break; 62 } 63 remaining -= nr; 64 } 65 66 return n - remaining; 67 } 68 69 public int available() throws IOException { 70 return 0; 71 } 72 73 public void close() throws IOException {} 74 75 public synchronized void mark(int readlimit) {} 76 77 public synchronized void reset() throws IOException { 78 throw new IOException("mark/reset not supported"); 79 } 80 81 public boolean markSupported() { 82 return false; 83 } 84 }
說明:
1.Closeable 接口表示可以關閉的數據源或目標。這個接口只有一個方法close()。
ByteArrayInputStream類
如果還是覺得上面的內容理解起來還是很抽象,很難懂。沒有關系,結合這個具體的InputStream類具體的子類ByteArrayInputStream類來看,會幫助你解開一部分困惑。計算機的學習就是這個樣子,后面的知識需要前面的知識作為鋪墊,前面的知識需要后面的知識才可以更深的理解。所以要前前后后的看一下,才可以真正的理解。
ByteArrayInputStream
包含一個內部緩沖區,該緩沖區包含從流中讀取的字節。內部計數器跟蹤read
方法要提供的下一個字節。關閉 ByteArrayInputStream 無效。此類中的方法在關閉此流后仍可被調用,而不會產生任何 IOException。
這是jdk文檔中關於此類的描述。說明:
1.內部緩沖區指的是buf數組
2.內部計數器就是指字段pos,可以將其看成是光標
3.關閉 ByteArrayInputStream 無效指的是,關閉流的close()方法,在此類中時空方法
這里就不給出ByteArrayInputStream類的方法列表里,因為大體上和InputStream類方法列表的描述是一樣的,只是方法的實現是不同的而已。
ByteArrayInputStream類源碼分析
源碼還是很有必要看一下的可以加強對此類的理解

1 public class ByteArrayInputStream extends InputStream { 2 3 // 保存字節輸入流數據的字節數組 4 protected byte buf[]; 5 6 // 下一個會被讀取的字節的索引 7 protected int pos; 8 9 // 用於標記輸入流當前位置,就是標記pos 10 protected int mark = 0; 11 12 // 字節流的長度 13 protected int count; 14 15 // 構造函數:創建一個內容為buf的字節流 16 public ByteArrayInputStream(byte buf[]) { 17 // 初始化“字節流對應的字節數組為buf” 18 this.buf = buf; 19 // 初始化“下一個要被讀取的字節索引號為0” 20 this.pos = 0; 21 // 初始化“字節流的長度為buf的長度” 22 this.count = buf.length; 23 } 24 25 // 構造函數:創建一個內容為buf的字節流,並且是從offset開始讀取數據,讀取的長度最多為length 26 public ByteArrayInputStream(byte buf[], int offset, int length) { 27 // 初始化“字節流對應的字節數組為buf” 28 this.buf = buf; 29 // 初始化“下一個要被讀取的字節索引號為offset” 30 this.pos = offset; 31 // 初始化“字節流的長度” 32 this.count = Math.min(offset + length, buf.length); 33 // 初始化“標記的字節流讀取位置” 34 this.mark = offset; 35 } 36 37 // 讀取下一個字節 38 public synchronized int read() { 39 return (pos < count) ? (buf[pos++] & 0xff) : -1; 40 } 41 42 // 將“字節流的數據寫入到字節數組b中” 43 // off是“字節數組b的偏移地址”,表示從數組b的off開始寫入數據 44 // len是“讀到b數組中的字節最大長度” 45 public synchronized int read(byte b[], int off, int len) { 46 if (b == null) { 47 throw new NullPointerException(); 48 } else if (off < 0 || len < 0 || len > b.length - off) { 49 throw new IndexOutOfBoundsException(); 50 } 51 52 if (pos >= count) { 53 return -1; 54 } 55 56 int avail = count - pos; 57 if (len > avail) { 58 len = avail; 59 } 60 if (len <= 0) { 61 return 0; 62 } 63 System.arraycopy(buf, pos, b, off, len); 64 pos += len; 65 return len;//從字節流中成功讀出的字節數 66 } 67 68 // 跳過“字節流”中的n個字節。 69 public synchronized long skip(long n) { 70 long k = count - pos; 71 if (n < k) { 72 k = n < 0 ? 0 : n; 73 } 74 75 pos += k; 76 return k;//成功跳過的字節數 77 } 78 79 // “能否讀取字節流的下一個字節” 80 public synchronized int available() { 81 return count - pos; 82 } 83 84 // 是否支持“標簽” 85 public boolean markSupported() { 86 return true; 87 } 88 89 // 保存當前位置。readAheadLimit在此處沒有任何實際意義 90 public void mark(int readAheadLimit) { 91 mark = pos; 92 } 93 94 // 重置“字節流的讀取索引”為“mark所標記的位置” 95 public synchronized void reset() { 96 pos = mark; 97 } 98 99 public void close() throws IOException { 100 } 101 }
真的是排版能力有限了。此博文僅作學習之用,歡迎指正。