星期六, 6月 02, 2007

[Java] IO Stream 的 read & write

[Java] IO Stream 的 read & write
摘自 Java I/O 技術,p.10

int 長度為 4 bytes,數值格式為 2's (二的補數),從 -2,147,483,648 ~ 2,147,483,647,以 big-endian 順序排序
byte 長度為 8 bits,數值格式為 2's(二的補數),從 -128 ~ 127

因 此,直接運用 byte 並不是最方便的,在串流類別中的許多方法,其說明文件說它們是用來讀寫 bytes;然而,它們真正傳回的 int 值(或接受的引數),是『無號位元組』(unsigned byte,即 0 ~ 255 之間的正整數)。事實上,在 Java 的基礎型態中並沒有這種資料型態,這種 int 是在內部被轉換成 byte。

例如,java.io.InputStream 的 read() 傳回資料的下一個位元組(byte),若是已達串流的末端,就傳回 -1。乍看之下,這不禁令人懷疑要如何分辨『串流資料中的 -1』與『串流結尾的 -1』?事實上,read() 傳回的並非 byte,從 read() 的原型可看出,它實際傳回的是 int:
public abstract int read() throws IOException

這個 int 並非值域在 -128 到 127 之間的 java byte,而是值域在 0 到 255 之間的一般無號位元組。因此可輕易地從該串流讀出合法資料中辨認出 -1。

同樣的問題也出現在 java.io.OutputStream 的 write()。它傳回 void,但以一個 int 為引數:
public abstract void write(int b) throws IOException

這 個 int 會被當成值域在 0 到 255 之間的無號位元組處理。然而沒有任何方式避免程式設計師傳入一個超出此範圍的 int 值。在這種情況下,較低的 8 bits 會被留下,而較高的 24 bits 會被丟棄。這如同『取 int b 除以 256 所剩的餘數,若餘數值為負,就再加上 256』的效果:
b = b % 256 >= 0 ? b % 256 : 256 + b % 256

或是下列這道簡單的位元運算之計算結果:
b = b & 0x000000FF;


在另一方面,那些會讀寫位元組陣列的方法,使用的是正牌的 Java byte,舉例來說,java.io.InputStream 中的兩個 read() 方法:
public int read(byte[] data) throws IOException
public int read(byte[] data, int offset, int length) throws
IOException

對 單一數字而言,一個 8bit 的 byte,和一個 32 bit 的 int 之間的差異,是微不足道的;不過,倘若讀人的是上千或上百萬的數字時,差異就很明顯了。事實上,一個 byte 在 Java 虛擬機器內部會用掉 4 byte 的空間,但是位元組陣列剛好只佔據它實際所需的空間。虛擬機器具備操作 byte 陣列的特殊指令,但沒有任何指令可以操作單一 byte,它們一律被提升成 int。

沒有留言: