1. 程式人生 > >Java 從流中讀取byte的奇怪現象,出現負值,詳解

Java 從流中讀取byte的奇怪現象,出現負值,詳解

其實一點都不奇怪,下面我們來詳細分析

首先看下面一段程式碼,程式碼的意思是將128寫入到檔案中,再從檔案中讀出一個byte輸出

    File f = new File("f1");
    FileOutputStream fos = new FileOutputStream(f);
    fos.write(128);
    fos.close();

    FileInputStream fis = new FileInputStream(f);
    int a = fis.read();
    System.out.println(a);

輸出結果為:

128

這符合我們的直觀感覺,寫入128,讀出來也是128

下面我們修改一下程式碼,將資料度入到byte數組裡,看看輸出會是什麼樣子,程式碼如下

    File f = new File("f1");
    FileOutputStream fos = new FileOutputStream(f);
    fos.write(128);
    fos.close();

    FileInputStream fis = new FileInputStream(f);
    byte[] b = new byte[1];
    fis.read(b, 0, 1);
    System.out.println
(b[0]);

輸出結果為

-128

好了,“奇怪”的現象出現了,這是為什麼呢?

首先,我們需要了解一些基礎知識,在Java中,byte的範圍為 -128 ~ 127,並沒有128這個數值;其次,讀者需要了解一下負數在Java中如何表示(即原碼、反碼、補碼的相關知識,請讀者自行谷歌)。

下面,我們來分析一下出現 -128 的原因:

首先,fos.write(128) 表示寫入 “128” 所代表的位元組,即 1000 0000,也就是說,檔案中當前包含一個位元組,8位依次為 1 0 0 0 0 0 0 0

當我們呼叫fis.read()時,該方法會返回一個無符號byte,也就說直接將1000 0000

翻譯為128,大家可以去看該方法的說明,返回值的範圍為0 ~ 255;所以我們得到了 128 的輸出;

當我們呼叫fis.read(b, 0, 1)時,相當於把檔案中第一個位元組讀入到了b[0]中,此時b[0]的二進位制表示為1000 0000,根據負數在Java中的表示方法,我們可以計算出,該二進位制序列的數值為 -128,也就是說這個過程並沒有將其轉化為無符號數值的過程,所以我們得到了 -128 的輸出。

那麼,我們如何解決這個問題呢?

首先,我們需要看一下fos.write(int a)這個方法,它的功能是寫入a代表的byte值,也就是說,該函式實際上是將a 的後八位寫入到檔案中 , 所以作者建議在使用該方法時,為了避免產生歧義,a 的範圍最好在 0 ~ 255 之間,初學者最好在 0 ~ 127 之間。(具體原因可以結合負數的表示規則自己想想哦~)。

迴歸正題,我們如何解決上文中的問題呢,即 “寫入128、讀出-128” 的問題,我們可以用下面的程式碼來解決。

    File f = new File("f1");
    FileOutputStream fos = new FileOutputStream(f);
    fos.write(128);
    fos.close();

    FileInputStream fis = new FileInputStream(f);
    byte[] b = new byte[1];
    fis.read(b, 0, 1);
    System.out.println(b[0] & 0xff);

也就是說,用b[0] & 0xff的方法得到b[0]的無符號值。

插入一個小問題,就是,b[0] | 0xff得到的是一個負值,而 & 得到的卻是一個正值。這裡根據作者的猜測,可能是如下原因,主要和 & 運算的步驟有關:

進行 b[0] & 0xff運算時的步驟如下:

  1. 因為0xff預設應該用int來儲存,所以首先將 b[0] 強制轉化為 int 型別表示,b[0] 的數值為-128,所以其二進位制表示為11111111 11111111 11111111 10000000
  2. 0xff的二進位制表示為 00000000 00000000 00000000 11111111
  3. 這兩個數做 & 運算後,得到 00000000 00000000 00000000 10000000,其表示的值為128

“或 運算”的過程類似,讀者可以自己推理一下