1. 程式人生 > >[六]JavaIO之 ByteArrayInputStream與ByteArrayOutputStream

[六]JavaIO之 ByteArrayInputStream與ByteArrayOutputStream

功能簡介

ByteArrayInputStream 和 ByteArrayOutputStream 提供了針對於字元陣列 byte [] 的標準的IO操作方式 image_5b976984_59d4 ByteArrayInputStream將會給一個byte buf[]   提供標準的IO操作方式 ByteArrayOutputStream則是將資料寫入到內部的位元組陣列中

ByteArrayInputStream 詳解

功能: 從提供的位元組陣列中,以IO的行為方式工作,進行讀取資料

ByteArrayInputStream欄位

protected byte[] buf
用於儲存由該流的建立者提供的 byte 陣列
也就是構造方法傳入
protected int count 個數
protected int mark 流中當前的標記位置
構造時預設將 ByteArrayInputStream 物件標記在位置零處
通過 mark() 方法可將其標記在緩衝區內的另一個位置處
通過 reset() 方法將當前緩衝區位置設定為此點
protected int mark = 0;定義時設定了預設值,如果不設定將為0
protected int pos 要從輸入流緩衝區中讀取的下一個字元的索引

ByteArrayInputStream構造方法

public ByteArrayInputStream(byte[] buf) 需要傳入byte buf[] 位元組陣列作為他的緩衝區
當前起始下標 pos  為0
count為陣列長度
mark位置為0
image_5b976984_3cbf
image_5b976984_6c8c
public ByteArrayInputStream(byte[] buf,                             int offset,                             int length)

傳入位元組陣列以及偏移量和長度
當前起始下標 pos  為 指定的偏移量
個數為offset+length 和 buf.length中小的那個
mark為偏移量起始地址
可以理解為,這個位元組陣列偏移量的部分才是資料來源,前面都沒關係
image_5b976984_73ec
image_5b976984_7824

read方法

讀取下一個位置的位元組
如果下一個位置 pos小於總個數
返回pos下標的位元組陣列資料
並且pos自增
image_5b976984_4062
& 0xff  :
Java中只有  有符號數,
型別提升時是按照符號位擴充套件的
對於正數,沒有什麼影響
對於負數,按照符號位擴充套件和按照0位擴充套件區別很大

按符號位擴充套件,也就是補符號位,值不變
按零位擴充套件,也就是補零時,相當於有符號數轉變為無符號數

所以在數值計算中,直接使用型別提升,數值不變
而對於編解碼時,需要進行轉換

&0xff這種方式就是來確保是按補零擴充套件
0xff預設為int型,是十六進位制,十進位制中表示為255,二進位制為32位,後八位為'1111 1111',其他24位均為0
a & 0xff 操作時,因為a為byte型,所以會將a自動轉化為int型(高位補1)
byte & 0xff操作一般將byte資料轉換成int型,最終的資料只有低8位有資料,其他位為0
簡單說就是讀取pos下標的元素,返回值為int

帶引數的read()方法
將資料讀取到b的off位置處

//從流中讀取資料到b[] 中,從off開始寫,寫len長度

public synchronized int read(byte b[], int off, int len) {

if (b == null) {//如果b為null 空指標

throw new NullPointerException();

} else if (off < 0 || len < 0 || len > b.length - off) {//如果偏移量小於0 或者寫入長度小於0 或者想要讀取的長度小於實際的長度了

throw new IndexOutOfBoundsException();

}



if (pos >= count) {//如果位置游標已經到了最後了,沒有資料可讀,返回-1

return -1;

}



int avail = count - pos;//可用個數為總個數count - 當前位置pos

if (len > avail) {//如果想要讀取的len比實際擁有的資料要長,那麼只讀取實際的個數

len = avail;

}

if (len <= 0) {

return 0;

}

System.arraycopy(buf, pos, b, off, len);//使用本地方法拷貝資料 buf 的pos位置開始拷貝,拷貝len個,到b的off位置

pos += len;//位置游標後移

return len;

}

read方法本質很簡單 就是一個數組,讀取一個,就游標移動下一個,pos就是記住位置的變數 讀取的就是指定下標的元素 image_5b976984_3d24

skip

image_5b976984_9e0
image_5b976984_5055

available

本質就是個陣列,所以可用個數就是總個數減去下一個字元的索引
image_5b976984_55e7

mark /markSupported /reset

ByteArrayInputStream支援mark和reset
而且 很顯然,mark方法的輸入引數是無效的
何處呼叫,何處就是標記點
呼叫reset就是pos設定到標記點

image_5b976984_5d94
為什麼mark 的引數無效?
很顯然,ByteArrayInputStream是操作字元陣列的,而且,這個陣列不是複製而來的
是直接通過引用指向的
也就是說整個的位元組陣列都在隨時可訪問的範圍內,要這個引數有什麼用呢
mark /markSupported /reset 三連的本質在於提供可重複讀的功能,所以對於不可逆的流需要快取
此處天然自帶可以隨時讀取某個下標的能力

close

ByteArrayInputStream的根本在於針對給定的某個位元組陣列,提供IO操作方式的統一形式
就好像你寫了個方法操作位元組陣列一樣,完全不涉及資源
所以無需關閉任何實質內容
通過close關閉ByteArrayInputStream之後,如果再次使用這個流
並不會丟擲異常
當然,流結束了,就不能再繼續使用了
所有方法列表 image_5b976984_53d2

ByteArrayOutputStream詳解

以IO的行為方式工作,將資料寫入到內部的位元組陣列中

ByteArrayOutputStream欄位

protected byte buf[];
儲存資料的緩衝區
protected int count;
緩衝區中的有效位元組數,每次寫入將會寫入到buf[count]處

ByteArrayOutputStream構造方法

構造方法只是設定內部位元組陣列這個緩衝區資料的大小
    public ByteArrayOutputStream() ; 預設長度為32位
image_5b976984_5f3
public ByteArrayOutputStream(int size) 只要引數值合法,建立指定個數的位元組陣列緩衝區
image_5b976984_3af3

write

write是輸出,引數都是他的輸出內容,只是不同的流輸出的目的不一樣,此處我們的輸出流的目的地是內部的位元組陣列
write(int) 將指定的位元組寫入此 byte 陣列輸出流
也就是寫入到內部的位元組陣列中
write(byte[], int, int) 將指定 byte 陣列中從偏移量 off 開始的 len 個位元組寫入此 byte 陣列輸出流
也就是寫入到內部的位元組陣列中
可以看得出來,他們都有使用 ensureCapacity在必要的時候進行擴充套件 擴充套件的行為是新建一個更大的,然後將原有陣列元素全部拷貝過去 保證空間足夠的情況下 write(int)  就是buf[count] = (byte)b; 對於write(byte[], int, int)  則是使用System.arraycopy image_5b976984_5bfb

writeTo(OutputStream)

因為ByteArrayOutputStream內部維護的是一個位元組陣列,所以可以直接作為OutputStream中write()方法的引數
程式碼很簡單,就是講內部的位元組陣列,轉存到入參指定的輸出流中
相當於把流中的資料重寫了一份到另外的輸出流
image_5b976984_123b

toString()

計算機所有的資料都是二進位制儲存,最小的單位是位元組,字元的編碼形式也正是位元組
所以,toString其實就是把位元組序列進行解碼

image_5b976984_571f  
int型別入參的方法,在JDK1.8  已經棄用
toString()使用平臺預設的字符集,通過解碼位元組將緩衝區內容轉換為字串
toString(String charsetName)   使用指定的 charsetName,通過解碼位元組將緩衝區內容轉換為字串

reset()

reset是重置的意思,ByteArrayOutputStream 使用buf[] 儲存資料,使用count指示位置
所以想要重新使用現在的緩衝區,拋棄原來所有的,只需要將count清零,每次的資料重新從0開始寫入位元組陣列即可
image_5b976984_7677
反正我們知道現在總共有多少有效位元組,原來寫入到buf中的可能多於count的那些位元組就放著好了,我們也不去使用

size()

count就是一直用來記錄有效個數的,所以直接返回count就是實際的size
image_5b976984_1f98

toByteArray()

轉換為位元組陣列,它本身就是一個位元組陣列
所以轉換比較簡單,只需要建立一個大小相同的位元組陣列,並且將資料拷貝過去即可
image_5b976984_5b2a

close()

ByteArrayOutputStream 寫入的是自己內部的位元組陣列
屬於記憶體資料,不涉及任何資源,所以close不需要做什麼
image_5b976985_5e3f