關於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拓展。  
}

       從源碼中我們得到的信息是直到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;  

    }  

這里它果斷的又將int強制轉成了byte(截取后八位)。於是總結下現在得到的信息是,java字節流把byte轉成int讀出來再轉回byte存起來。何必呢?

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

[java] view plaincopy

if (pos >= count)  return -1;  

[java] view plaincopy

if (pos >= count)  return -1;  

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

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM