1. 程式人生 > >關於java位元組流的read()方法返回值為int的思考

關於java位元組流的read()方法返回值為int的思考

我們都知道javaio操作分為位元組流和字元流,對於位元組流,顧名思義是按位元組的方式讀取資料,所以我們常用位元組流來讀取二進位制流(如圖片,音樂 等檔案)。問題是為什麼位元組流中定義的read()方法返回值為int型別呢?既然它一次讀出一個位元組資料為什麼不返回byte型別呢?(不知道有沒有人 和我有同樣的困惑,不過既然有了問題咱就得解決。)

於是我翻閱了java的原始碼,下面先把原始碼貼出來(以BufferedInputStream/BufferedOutputStream為例):

//BufferedInputStream中的read()方法的實

   public synchronized int read() throws IOException {  

       if (pos >= count) {  

           fill();  

       if (pos >= count)   

           return -1;  

       }  

       return getBufIfOpen()[pos++] & 0xff;//這邊getBufIfOpen()返回的是byte[],& 0xff是為了保證由char型別向上拓展成int的時候,不進行符號拓展,而是0拓展。

   public synchronized int read() throws IOException {  

       if (pos >= count) {  

           fill();  

       if (pos >= count)   

           return -1;  

       }  

       return getBufIfOpen()[pos++] & 0xff;//這邊getBufIfOpen()返回的是byte[],& 0xff是為了保證由char型別向上拓展成int的時候,不進行符號拓展,而是0拓展。

從原始碼中我們得到的資訊是直到getBufIfOpen()方法返回,我們得到的都是byte型別,可是為什麼方法的最終返回值是

int

首先我先簡單解釋下符號擴充套件,這是指由byte向上轉化成更寬的型別時,是擴充套件的符號位。這對於正數補0,負數補1,例如,定義byte b = -1;在計算機內部它是用八位1111 1111表示的,當擴充套件成32位整型的時候,一般情況下是1111 1111 1111 1111 1111 1111 1111 1111,即符號擴充套件,而對於無符號擴充套件,也稱為0擴充套件,其結果是0000 0000 0000 0000 0000 0000 1111 1111(實際上這樣一來值已經變成255了)。過於向上轉型和強制向下轉型的進一步討論,我在以後再說。這裡要說的是我們能從java原始碼中得到的第二 個資訊,即上面的註釋部分,read()方法的最後一行把讀到的位元組0擴充套件成了int,也就是說如果我們直接讀出來這個值可能就是不對了。這裡我又疑惑 了,為什麼BufferedOutputStream中的writer()方法能正確讀出位元組呢?所以我再去查下對應的原始碼:

public synchronized void write(int b) throws IOException {  

        if (count >= buf.length) {  

            flushBuffer();  

        }  

        buf[count++] = (byte)b;  

    }  

public synchronized void write(int b) throws IOException {  

        if (count >= buf.length) {  

            flushBuffer();  

        }  

        buf[count++] = (byte)b;  

    }  

可以看到,這裡它果斷的又將int強制轉成了byte(擷取後八位)。於是總結下現在得到的資訊是,java位元組流把byte轉成int讀出來再轉回byte存起來。何必呢?

經過一番思考,我初步有了答案:在用輸入流讀取一個byte資料時,有時會出現連續8個1的情況,這個值在計算機內部表示-1,正好符合了流結束標記。所以為了避免流操作資料提前結束,將讀到的位元組進行int型別的擴充套件。保留該位元組資料的同時,前面都補0,避免出現-1的情況。而真正讀到檔案最後結束是通過這句實現的:

if (pos >= count)  return -1;  

if (pos >= count)  return -1;  

所以我們使用的-1這個結束標誌是通過這句返回的,而不是輸入流讀到了一個-1

這樣一來就解決了我們前面的疑惑,也證實了確實有這樣實現的必要。對於字元流的讀寫也可以用類似的方法分析,這裡不再贅述。