先來看ByteArrayOutputStream類中write()方法:
// Writes the specified byte to this byte array output stream.
public synchronized void write(int b) {
ensureCapacity(count + 1);
buf[count] = (byte) b;
count += 1;
}
/**
* Writes len bytes from the specified byte array
* starting at offset off to this byte array output stream.
*/
public synchronized void write(byte b[], int off, int len) {
if ((off < 0) || (off > b.length) || (len < 0) ||
((off + len) - b.length > 0)) {
throw new IndexOutOfBoundsException();
}
ensureCapacity(count + len);
System.arraycopy(b, off, buf, count, len);
count += len;
}
這個類也是通過向數組中定入值來進行數值傳遞的,而字節數組的大小可以在創建ByteArrayOutputStream時通過構造函數指定,默認的大小爲32.如果在調用write()方法時,都會確保字節數組的容量。如果過小,會自動進行擴容操作。這樣就可以把需要的數據寫到字節數組中去了。還可以通過調用writeTo()方法可以寫入到其他輸出流中,源代碼如下:
/**
* Writes the complete contents of this byte array output stream to
* the specified output stream argument, as if by calling the output
* stream's write method using out.write(buf, 0, count).
*/
public synchronized void writeTo(OutputStream out) throws IOException {
out.write(buf, 0, count);
}
繼續來看ByteArrayInputStream類,這個類可以從字節數組中讀出數據,具體的源代碼如下:
public synchronized int read() {
return (pos < count) ? (buf[pos++] & 0xff) : -1;
}
public synchronized int read(byte b[], int off, int len) {
if (b == null) {
throw new NullPointerException();
} else if (off < 0 || len < 0 || len > b.length - off) {
throw new IndexOutOfBoundsException();
}
if (pos >= count) {
return -1;
}
int avail = count - pos;
if (len > avail) {
len = avail;
}
if (len <= 0) {
return 0;
}
System.arraycopy(buf, pos, b, off, len);
pos += len;
return len;
}
同時也提供了其他的一些方法,如可以跳讀字節的skip()方法、查看剩餘有效字節的avaible()方法等等,有興趣的可以自己去看。下面來舉一個具體應用的例子,如下:
byte[] bytes = { 0,2, 3, 4, 5 };
try (ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteArrayInputStream in = new ByteArrayInputStream(bytes);){
out.write(bytes);
System.out.println(out.size());//5
System.out.println(in.read());//解
in.skip(1);//2
in.mark(4);
System.out.println(in.read());//3
in.reset();// 從索引爲2的地方重新開始讀
System.out.println(in.read());//3
System.out.println(in.read());
} catch (IOException e) {
e.printStackTrace();
}
4、StringBufferInputStream
這個類現在已經不提倡使用了,個人覺得是因爲編碼的原因吧。查看這個類後的源代碼,如下:
public synchronized int read() {
return (pos < count) ? (buffer.charAt(pos++) & 0xFF) : -1;
}
public synchronized int read(byte b[], int off, int len) {
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();
}
if (pos >= count) {
return -1;
}
if (pos + len > count) {
len = count - pos;
}
if (len <= 0) {
return 0;
}
String s = buffer;
int cnt = len;
while (--cnt >= 0) {
b[off++] = (byte)s.charAt(pos++);
}
return len;
}
發現,其實這個類是將字符串中的字符轉換爲字節進行讀取的,如果這個字符串的字符全部爲ISO-8859-1編碼所能表示的,那肯定能正常讀取。但是通常Java都是Unicode編碼,兩個字符,所以如果其中出現了Unicode字符的時候,例如中文,讀取就會不準確。如下舉例:
String str = "馬智AB";
StringBufferInputStream st = new StringBufferInputStream(str);
byte[] j = new byte[16];
st.read(j);
System.out.println(new String(j)); //lzAB
原因可能大家也知道了,兩個read()方法在獲取到這個字符串的字符(s.charAt())後,強制轉換爲byte或與0xff相與,這樣的結果只能導致取到低8位的編碼,而對於兩個字節編碼的漢字來說,肯定會產生錯誤。