1. 程式人生 > >java無格式int檔案寫入和讀取

java無格式int檔案寫入和讀取

今天寫一個小程式,需要將int陣列寫入檔案,然後再讀出來。為了節省空間,打算採用直接把每個int的位元組碼寫入檔案,讀的時候也是按照int的位元組碼直接進行讀取,省略了逗號、換行符等格式編碼。

第一次嘗試:

FileOutputStream fOut = new FileOutputStream(f);
for(int i = 0 ; i < intArray.length ; i++){
	fOut.write(intArray[i]);
}

省略了異常處理,FileOutputStream能直接輸出int,感覺還挺方便。但是讀取的時候,問題就來了,以下為讀取的程式碼:

byte[] byteA = new byte[Integer.SIZE / 8];
while(fInput.read(byteA) > 0){
	System.out.println(this.byteArrayToInt(byteA));
}
		

每次讀取4個byte,然後將按照位運算轉化為int,流程很簡單,但是執行起來有問題。

假設我在檔案中輸入了128,512兩個數字,檔案中只要存著以下內容即可保證程式正常執行:

00000000 00000000 00000000 10000000 00000000 00000000 00000010 00000000

但是,檔案中實際存著的卻是10000000 00000000原來使用FileOutputStream直接輸出int,只會擷取int中最低的一個八位組,丟棄其他高位八位組。

因此,還是需要將int轉化為byte[]後再輸出到檔案。

第二次嘗試:

增加了intToByteArray的轉換,第一次我是這麼寫的,基礎不紮實

……
    for(int i = 0 ; i < intArray.length ; i++){
		fOut.write(this.intToByteArray(intArray[i]));
	}
……
private byte[] intToByteArray(int value){
	byte[] byteArray = new byte[4];
	byteArray[0] = (byte) (value & 0xFF);
	byteArray[1] = (byte) (value & 0xFF00);
	byteArray[2] = (byte) (value & 0xFF0000);
	byteArray[3] = (byte) (value & 0xFF000000);
	return byteArray;
}

運行了一遍後,妥妥的有錯,改成如下所示:

private byte[] intToByteArray(int value){
	byte[] byteArray = new byte[4];
	byteArray[0] = (byte) (value & 0xFF);
	byteArray[1] = (byte) (value >> 8  & 0xFF);
	byteArray[2] = (byte) (value >> 16 & 0xFF);
	byteArray[3] = (byte) (value >> 24 & 0xFF);
	return byteArray;
}

即可向檔案中寫入int的byte[4]編碼。

然後是讀取的程式碼,只要保證讀寫大小端法一致就行,沒有硬性要求

……
    byte[] byteA = new byte[Integer.SIZE / 8];
    while(fInput.read(byteA) > 0){
    	System.out.println(this.byteArrayToInt(byteA));
    }
……
private int byteArrayToInt(byte[] byteArray){
    if(byteArray.length != 4){
		return 0;
	}
	int value = byteArray[0];
	value |= byteArray[1] << 8;
	value |= byteArray[2] << 16;
	value |= byteArray[3] << 24;
	return value;
}

每次讀取4個byte,將其轉為int,讀取是沒問題,但是轉換有問題。

假設將1007寫入檔案,即00000000 00000000 00000011 11101111,byte[]讀出來後,會顯示為[-17,3,0,0],執行過我的byteArrayToInt方法後,最終結果為-17。經過測試發現,只要最後一個八位組的值為負,最終結果就是最後一個八位組的顯示值,如果為正,則可正常轉換。

問題就在於int value = byteArray[0],這個byte與int的型別轉換上,-17在byte中為11101111,轉為int後,會補位成為11111111 11111111 11111111 11101111,之後的幾次或運算就不會有任何效果。同理,char轉int、int轉long等低轉高時,都需要注意補位的問題。

將程式碼做如下修改,即可解決問題:

private int byteArrayToInt(byte[] byteArray){
    if(byteArray.length != 4){
		return 0;
	}
	int value = byteArray[0] & 0xFF;
	value |= byteArray[1] << 8;
	value |= byteArray[2] << 16;
	value |= byteArray[3] << 24;
	return value;
}

現將最低的八位組用0xFF“重置“一遍,之後即可正常執行。

至此,將int陣列寫入檔案並讀取的程式碼基本完成。

總結

1、FileOutputStream直接輸出int,會擷取最低的八位組輸出,拋棄其餘高位

2、byte轉int、char轉int、int轉long等低轉高時,需要注意補位。