一、SequenceInputStream源碼——可以順序讀取多個輸入Stream的裝飾器類
SequenceInputStream.class 的UML關係圖,如下所示:

SequenceInputStream.class的源碼,如下所示:
package java.io;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.Vector;
public
class SequenceInputStream extends InputStream {
//順序(序列化)裝載多個被裝飾輸入Stream的集合,一般是Vector實例
Enumeration<? extends InputStream> e;
InputStream in;//順序(序列化)裝載多個被裝飾輸入Stream的集合中當前正在被SequenceInputStream 對象使用的被裝飾的輸入Stream
//構造函數,傳入一個順序(序列化)裝載多個被裝飾輸入Stream的集合
public SequenceInputStream(Enumeration<? extends InputStream> e) {
this.e = e;
try {
nextStream();
} catch (IOException ex) {
// This should never happen
throw new Error("panic");
}
}
//構造函數,可以將2個被裝飾的輸入Stream放入到集合中
public SequenceInputStream(InputStream s1, InputStream s2) {
Vector<InputStream> v = new Vector<>(2);
v.addElement(s1);
v.addElement(s2);
e = v.elements();
try {
nextStream();
} catch (IOException ex) {
// This should never happen
throw new Error("panic");
}
}
//獲取集合中下一個被裝飾的輸入Stream
final void nextStream() throws IOException {
if (in != null) {
in.close();//先關閉當前被裝飾的輸入Stream
}
if (e.hasMoreElements()) {//如果集合中還有被裝飾的輸入Stream
in = (InputStream) e.nextElement();//獲取集合中下一個被裝飾的輸入Stream
if (in == null)
throw new NullPointerException();//如果集合中下一個被裝飾的輸入Stream為null,拋出一個NullPointerException
}
else in = null;//如果集合中沒有了被裝飾的輸入Stream,將當前正在使用的被裝飾的輸入Stream置為null
}
//判斷當前正在使用的被裝飾的輸入Stream是否還有可以讀取的字節數據
public int available() throws IOException {
if (in == null) {
return 0; // no way to signal EOF from available()
}
return in.available();
}
//從SequenceInputStream 對象的集合(該集合放着多個被裝飾的輸入Stream)中讀取1個字節
public int read() throws IOException {
while (in != null) {//如果in!=null,則説明當前這個SequenceInputStream 對象的集合中還有被裝飾的輸入Stream沒有關閉
int c = in.read();//從當前正在使用的被裝飾的被裝飾輸入Stream中讀取1個字節
if (c != -1) {//c != -1説明從當前正在使用的被裝飾輸入Stream中讀取到了字節
return c;//返回讀取到的這個字節
}
nextStream();//如果c==-1説明當前正在使用的被裝飾輸入Stream中字節(byte)數據已經讀完,獲取SequenceInputStream 對象的集合中下一個被裝飾的輸入Stream
}
return -1;//如果SequenceInputStream 對象的集合中所有被裝飾的輸入Stream中的字節(byte)數據都已經讀完,返回-1
}
//從SequenceInputStream 對象的集合(該集合放着多個被裝飾的輸入Stream)中讀取len個字節,放入到byte[]數組b的[off,off+len)(左閉右開,不包括off+len)索引位置
public int read(byte b[], int off, int len) throws IOException {
if (in == null) {//如果in==null,則説明當前這個SequenceInputStream 對象的集合中所有被裝飾的輸入Stream都已經關閉
return -1;
} else if (b == null) {
throw new NullPointerException();//如果byte[]數組b==null,拋出一個NullPointerException
} else if (off < 0 || len < 0 || len > b.length - off) {//相當於off + len > b.length(源碼中這樣寫代碼的好處我沒看出來)
throw new IndexOutOfBoundsException();
} else if (len == 0) {
return 0;//要從SequenceInputStream 對象的集合(該集合放着至少2個被裝飾的輸入Stream)中讀取的len個字節==0時,返回0
}
do {
int n = in.read(b, off, len);//從當前正在使用的被裝飾的輸入Stream中讀取len個字節,放入到byte[]數組b的[off,off+len)(左閉右開,不包括off+len)索引位置
if (n > 0) {
return n;//只要能從當前正在使用的被裝飾的輸入Stream中讀取到字節,則返回讀取的數量
}
nextStream();//此時n==-1,説明當前正在使用的被裝飾的輸入Stream中字節(byte)數據已經讀完,獲取SequenceInputStream 對象的集合中下一個被裝飾的輸入Stream
} while (in != null);//SequenceInputStream 對象的集合中下一個被裝飾的輸入Stream為null時,跳出循環,返回-1
return -1;
}
//順序關閉SequenceInputStream 對象的集合中所有被裝飾的輸入Stream
public void close() throws IOException {
do {
nextStream();
} while (in != null);
}
}
1.1、SequenceInputStream的read()函數和nextStream()函數
package java.io;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.Vector;
public
class SequenceInputStream extends InputStream {
...省略部分代碼...
//順序(序列化)存儲多個被裝飾的輸入Stream的集合,一般是Vector實例
Enumeration<? extends InputStream> e;
InputStream in;//順序(序列化)裝載多個被裝飾輸入Stream的集合中當前正在被SequenceInputStream 對象使用的被裝飾的輸入Stream
//獲取集合中下一個被裝飾的輸入Stream
final void nextStream() throws IOException {
if (in != null) {
in.close();//先關閉當前被裝飾的輸入Stream
}
if (e.hasMoreElements()) {//如果集合中還有被裝飾的輸入Stream
in = (InputStream) e.nextElement();//獲取集合中下一個被裝飾的輸入Stream
if (in == null)
throw new NullPointerException();//如果集合中下一個被裝飾的輸入Stream為null,拋出一個NullPointerException
}
else in = null;//如果集合中沒有了被裝飾的輸入Stream,將當前正在使用的被裝飾的輸入Stream置為null
}
//從SequenceInputStream 對象的集合(該集合放着多個被裝飾的輸入Stream)中讀取1個字節
public int read() throws IOException {
while (in != null) {//如果in!=null,則説明當前這個SequenceInputStream 對象的集合中還有被裝飾的輸入Stream沒有關閉
int c = in.read();//從當前正在使用的被裝飾的被裝飾輸入Stream中讀取1個字節
if (c != -1) {//c != -1説明從當前正在使用的被裝飾輸入Stream中讀取到了字節
return c;//返回讀取到的這個字節
}
nextStream();//如果c==-1説明當前正在使用的被裝飾輸入Stream中字節(byte)數據已經讀完,獲取SequenceInputStream 對象的集合中下一個被裝飾的輸入Stream
}
return -1;//如果SequenceInputStream 對象的集合中所有被裝飾的輸入Stream中的字節(byte)數據都已經讀完,返回-1
}
...省略部分代碼...
}
如果使用者用的是2個被裝飾的輸入Stream(此處為FileInputStream),構造的SequenceInputStream的對象,如下所示(偽代碼):
is1 = new FileInputStream("D:\\data1.txt");
is2 = new FileInputStream("D:\\data2.txt");
sequenceInputStream = new SequenceInputStream(is1, is2);
那麼,SequenceInputStream對象中Vector集合的容量是2,如果此時執行SequenceInputStream.class::read()函數。
//偽代碼
int readByte = -1;
while ((readByte = sequenceInputStream.read()) != -1) {
System.out.print((char) readByte);
}
過程如下(假設2個被裝飾的輸入Stream(此處為FileInputStream)中的字節數據如下):

①、先執行第1個被裝飾的輸入Stream(也是Vector集合的第1個元素)的read()函數,直到該函數返回-1,如下所示:

②、關閉第1個被裝飾的輸入Stream(也是Vector集合的第1個元素),再執行第2個被裝飾的輸入Stream(也是Vector集合的第2個元素)的read()函數,直到該函數返回-1,如下所示:

1.1.1、使用舉例
下面這個例子就恰當的使用SequenceInputStream的read()函數;
-
我的windows操作系統的D盤根目錄下有2個txt文件,一個是data1.txt,另一個是data2.txt文件,這2個文件中總共有30個字節,如下所示:
![clipboard]()
-
使用者可以用一個SequenceInputStream對象裝飾2個被裝飾的輸入Stream(此處為FileInputStream),如下代碼所示:
package com.chelong.StreamAndReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.SequenceInputStream;
public class SequenceInputStreamTest {
public static void main(String[] args) {
InputStream is1 = null;
InputStream is2 = null;
SequenceInputStream sequenceInputStream = null;
try {
is1 = new FileInputStream("D:\\data1.txt");
is2 = new FileInputStream("D:\\data2.txt");
sequenceInputStream = new SequenceInputStream(is1, is2);
int readByte = -1;
while ((readByte = sequenceInputStream.read()) != -1) {
System.out.print((char) readByte);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//此處省略關閉所有的Stream的代碼
}
}
}
程序運行結果,如下所示:

1.2、SequenceInputStream的read(byte b[], int off, int len)函數和nextStream()函數
package java.io;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.Vector;
public
class SequenceInputStream extends InputStream {
...省略部分代碼...
//順序(序列化)裝載多個被裝飾輸入Stream的集合,一般是Vector實例
Enumeration<? extends InputStream> e;
InputStream in;//順序(序列化)裝載多個被裝飾輸入Stream的集合中當前正在被SequenceInputStream 對象使用的被裝飾的輸入Stream
//獲取集合中下一個被裝飾的輸入Stream
final void nextStream() throws IOException {
if (in != null) {
in.close();//先關閉當前被裝飾的輸入Stream
}
if (e.hasMoreElements()) {//如果集合中還有被裝飾的輸入Stream
in = (InputStream) e.nextElement();//獲取集合中下一個被裝飾的輸入Stream
if (in == null)
throw new NullPointerException();//如果集合中下一個被裝飾的輸入Stream為null,拋出一個NullPointerException
}
else in = null;//如果集合中沒有了被裝飾的輸入Stream,將當前正在使用的被裝飾的輸入Stream置為null
}
//從SequenceInputStream 對象的集合(該集合放着多個被裝飾的輸入Stream)中讀取len個字節,放入到byte[]數組b的[off,off+len)(左閉右開,不包括off+len)索引位置
public int read(byte b[], int off, int len) throws IOException {
if (in == null) {//如果in==null,則説明當前這個SequenceInputStream 對象的集合中所有被裝飾的輸入Stream都已經關閉
return -1;
} else if (b == null) {
throw new NullPointerException();//如果byte[]數組b==null,拋出一個NullPointerException
} else if (off < 0 || len < 0 || len > b.length - off) {//相當於off + len > b.length(源碼中這樣寫代碼的好處我沒看出來)
throw new IndexOutOfBoundsException();
} else if (len == 0) {
return 0;//要從SequenceInputStream 對象的集合(該集合放着至少2個被裝飾的輸入Stream)中讀取的len個字節==0時,返回0
}
do {
int n = in.read(b, off, len);//從當前正在使用的被裝飾的輸入Stream中讀取len個字節,放入到byte[]數組b的[off,off+len)(左閉右開,不包括off+len)索引位置
if (n > 0) {
return n;//只要能從當前正在使用的被裝飾的輸入Stream中讀取到字節,則返回讀取的數量
}
nextStream();//此時n==-1,説明當前正在使用的被裝飾的輸入Stream中字節(byte)數據已經讀完,獲取SequenceInputStream 對象的集合中下一個被裝飾的輸入Stream
} while (in != null);//SequenceInputStream 對象的集合中下一個被裝飾的輸入Stream為null時,跳出循環,返回-1
return -1;
}
...省略部分代碼...
}
如果使用者用的是2個被裝飾的輸入Stream(此處為FileInputStream),構造的SequenceInputStream的對象,如下所示(偽代碼):
is1 = new FileInputStream("D:\\data1.txt");
is2 = new FileInputStream("D:\\data2.txt");
sequenceInputStream = new SequenceInputStream(is1, is2);
那麼,SequenceInputStream對象中Vector集合的容量是2,並且假設這2個被裝飾的輸入Stream(此處為FileInputStream)中的字節數據如下:

如果此時執行SequenceInputStream.class::read()函數。接下來使用SequenceInputStream對象讀取字節數據到使用者創建的byte[]數組,如果使用者創建的字節數組byte[]的長度>=第1個被裝飾的輸入Stream中的所有字節個數,比如,使用者創建的byte[]數組的長度為12,如下所示(偽代碼):
int readByte = -1;
byte[] buff = new byte[12];
while ((readByte = sequenceInputStream.read(buff, 0, buff.length)) != -1) {
for (int i = 0; i < readByte; i++) {
System.out.print((char) buff[i]);
}
}
整個執行過程如下:
①、第1次進入read()函數

②、第2次進入read()函數(重點是當前正在使用的被裝飾的輸入Stream中的字節數據已經讀取完了時,再次讀取,會返回-1,不會返回0)

③、第3次進入read()函數

④、第4次進入read()函數(重點是當前正在使用的被裝飾的輸入Stream中的字節數據已經讀取完了時,再次讀取,會返回-1,不會返回0)

最終使用者創建的byte[]數組中的字節(byte)數據,如下所示:

1.2.1、使用舉例
下面這個例子就恰當的使用SequenceInputStream的read()函數;
-
我的windows操作系統的D盤根目錄下有2個txt文件,一個是data1.txt,另一個是data2.txt文件,這2個文件中總共有30個字節,如下所示:
![clipboard]()
-
使用者可以用一個SequenceInputStream對象裝飾2個被裝飾的輸入Stream(此處為FileInputStream),如下代碼所示:
package com.chelong.StreamAndReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.SequenceInputStream;
import java.util.Vector;
public class SequenceInputStreamTest {
public static void main(String[] args) {
InputStream is1 = null;
InputStream is2 = null;
SequenceInputStream sequenceInputStream = null;
try {
is1 = new FileInputStream("D:\\data1.txt");
is2 = new FileInputStream("D:\\data2.txt");
Vector<InputStream> vector = new Vector<InputStream>();
vector.addElement(is1);
vector.addElement(is2);
sequenceInputStream = new SequenceInputStream(vector.elements());
int readByte = -1;
byte[] buff = new byte[12];
while ((readByte = sequenceInputStream.read(buff, 0, buff.length)) != -1) {
for (int i = 0; i < readByte; i++) {
System.out.print((char) buff[i]);
}
}
System.out.println();
System.out.println("最終留在byte[]數組buff中的字節:");
for (byte b : buff) {
System.out.print((char) b);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (is1 != null) is1.close();
if (is2 != null) is1.close();
if (sequenceInputStream != null) sequenceInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
程序運行結果,如下所示:

二、Vector.class的一些函數説明
Vector 與 ArrayList 一樣,也是通過數組實現的,不同的是它支持線程的同步,即某一時刻只有一個線程能夠寫 Vector,避免多線程同時寫而引起的不一致性,但實現同步需要很高的花費,因此,訪問它比訪問 ArrayList慢。Vector的UML圖,如下所示:

2.1、構造函數
| 函數名 | 函數説明 |
|---|---|
| public Vector() | 此構造函數創建的Vector中,Object[]數組的初始長度為10,capacityIncrement=0(capacityIncrement表示擴容時Object[]數組增加的長度,如果等於0的話,當Object[]數組需要擴容時,新的數組長度=2*舊數組的長度,但是新的數組長度最大為2^31-8) |
| public Vector(int initialCapacity) | 此構造函數創建的Vector中,Object[]數組的初始長度為initialCapacity,capacityIncrement=0(capacityIncrement表示擴容時Object[]數組增加的長度,如果等於0的話,當Object[]數組需要擴容時,新的數組長度=2*舊數組的長度,但是新的數組長度最大為2^31-8) |
| public Vector(int initialCapacity, int capacityIncrement) | 此構造函數創建的Vector中,Object[]數組的初始長度為initialCapacity,capacityIncrement=capacityIncrement(capacityIncrement表示擴容時Object[]數組增加的長度,如果等於0的話,當Object[]數組需要擴容時,新的數組長度=2*舊數組的長度,但是新的數組長度最大為2^31-8) |
| public Vector(Collection<? extends E> c) | 此構造函數創建的Vector中,Object[]數組的初始長度為傳入集合Collection<? extends E> c的長度,capacityIncrement=0(capacityIncrement表示擴容時Object[]數組增加的長度,如果等於0的話,當Object[]數組需要擴容時,新的數組長度=2*舊數組的長度,但是新的數組長度最大為2^31-8) |
2.2、常用函數
| 函數名 | 函數説明 |
|---|---|
| boolean add(E o) | 此函數將指定的元素追加到此Vector的末尾,該函數與addElement()函數的區別是,該()函數是List.interface接口規定的函數,addElement()函數是Vector自己實現的(接口中沒有規定addElement()函數) |
| void add(int index, E element) | 此函數將指定的元素插入此Vector中的指定索引位置 |
| boolean addAll(Collection<? extends E> c) | 此函數將指定Collection中的所有元素追加到此Vector的末尾 |
| boolean addAll(int index, Collection<? extends E> c) | 此函數將指定Collection中的所有元素插入到此Vector中的指定索引位置 |
| void addElement(E obj) | 此函數將指定的元素追加到此Vector的末尾,這個函數與add()函數的區別是,add()函數是List.interface接口規定的函數,這個函數是Vector自己實現的(接口中沒有規定該函數) |
| int capacity() | 此函數返回此Vector的當前容量 |
| void clear() | 此函數從此Vector中刪除所有元素 |
| Object clone() | 此函數返回此Vector的克隆對象 |
| boolean contains(Object elem) | 如果此Vector包含指定的元素,則此函數返回true |
| boolean containsAll(Collection<?> c) | 如果此Vector包含指定Collection中的所有元素,則此函數返回true |
| void copyInto(Object[] anArray) | 此方法將此向量的組件複製到指定的數組中 |
| E elementAt(int index) | 此函數返回Vector指定索引處的元素 |
| Enumeration |
此函數返回此Vector中所包含的所有元素的枚舉。 |
| void ensureCapacity(int minCapacity) | 此函數可增加此Vector的容量,以確保它至少可以保存最小容量元素個數 |
| boolean equals(Object o) | 此函數將指定的Object與此Vector進行比較以獲得相等性 |
| E firstElement() | 返回此Vector的第一個元素(位於Object[]數組索引 0 處的元素) |
| E get(int index) | 返回Vector中指定索引位置的元素 |
| int indexOf(Object elem) | 搜索給定參數的第一個匹配項,使用 equals ()函數測試相等性 |
| int indexOf(Object elem, int index) | 搜索給定參數的第一個匹配項,從 index 處開始搜索,並使用 equals()函數測試其相等性 |
| void insertElementAt(E obj, int index) | 將指定對象作為此Vector中的元素插入到指定的 索引位置 |
| boolean isEmpty() | 測試此Vector中的是否不包含任何元素 |
| E lastElement() | 返回此Vector的最後一個元素(位於Object[]數組索引 Object[].length-1 處的元素) |
| int lastIndexOf(Object elem) | 返回指定的對象在此Vector中最後一個匹配項的索引 |
| int lastIndexOf(Object elem, int index) | 從指定的索引處開始向後搜索指定的對象,並返回搜索到的最後一個索引 |
| E remove(int index) | 移除此Vector中指定索引位置的元素 |
| boolean remove(Object o) | 移除此Vector中指定元素的第一個匹配項,如果此Vector不包含該元素,則所有元素保持不變,並返回false |
| boolean removeAll(Collection<?> c) | 從此Vector中移除包含在指定 Collection 中的所有元素 |
| void removeAllElements() | 從此Vector中移除全部元素,並設置elementCount=0(該變量表示此Vector對象中有效元素的數量),Object[]數組的長度不變。 |
| void removeElementAt(int index) | 刪除指定索引處的元素 |
| protected void removeRange(int fromIndex, int toIndex) | 從此 Vector 中移除索引位於 [fromIndex, toIndex)(左閉右開)之間的所有元素 |
| boolean retainAll(Collection<?> c) | 如果此Vector中包含指定 Collection 中的所有元素,此函數返回true |
| E set(int index, E element) | 用指定的元素替換此Vector中指定索引處的元素 |
| void setElementAt(E obj, int index) | 將此Vector指定 索引處的元素設置為指定的另一個元素 |
| void setSize(int newSize) | 設置此Vector的大小 |
| int size() | 返回此Vector中的元素數 |
| List |
返回此 Vector的子集,該子集的元素範圍為 [fromIndex, toIndex)(左閉右開)索引位置的所有元素 |
| Object[] toArray() | 返回一個Object[]數組,包含此Vector中以正確順序存放的所有元素 |
| String toString() | 返回此Vector的字符串表示形式,其中包含每個元素的 String 表示形式 |
