new IO學習筆記(二)之字節存放順序
細談字節存放順序問題:
字節序,又稱端序,尾序,英文:Endianness。在計算機科學領域中,字節序是指存放多字節數據的字節(byte)的順序,典型的情況是整數在內存中的存放方式和網絡傳輸的傳輸順序。Endianness有時候也可以用指位序(bit)。
一般而言,字節序指示了一個UCS-2字符的哪個字節存儲在低地址。如果LSByte在MSByte的前麵,即LSB為低地址,則該字節序是小端序;反之則是大端序。在網絡編程中,字節序是一個必須被考慮的因素,因為不同的處理器體係可能采用不同的字節序。在多平台的代碼編程中,字節序可能會導致難以察覺的bug。
處理器體係:
- x86,MOS Technology 6502,Z80,VAX,PDP-11等處理器為Little endian。
- Motorola 6800,Motorola 68000,PowerPC 970,System/370,SPARC(除V9外)等處理器為Big endian
- ARM, PowerPC (除PowerPC 970外), DEC Alpha, SPARC V9, MIPS, PA-RISC and IA64的字節序是可配置的。
網絡序
網絡傳輸一般采用大端序,也被稱之為網絡字節序,或網絡序。IP協議中定義大端序為網絡字節序。
伯克利socket API定義了一組轉換函數,用於16和32bit整數在網絡序和本機字節序之間的轉換。htonl,htons用於本機序轉換到網絡序;ntohl,ntohs用於網絡序轉換到本機序。
--------------------------------------------------------------------------------------------------------------------------------------------------
代碼段一:
ByteBuffer buf = ByteBuffer.wrap(new byte[10]);
buf.asCharBuffer().put("abcde");
System.out.println(Arrays.toString(buf.array()));
System.out.println("----------------------------------------------");
buf.rewind();
buf.order(ByteOrder.BIG_ENDIAN);
buf.asCharBuffer().put("abcde");
System.out.println(Arrays.toString(buf.array()));
System.out.println("----------------------------------------------");
buf.rewind();
buf.order(ByteOrder.LITTLE_ENDIAN);
buf.asCharBuffer().put("abcde");
System.out.println(Arrays.toString(buf.array()));
打印結果:
[0, 97, 0, 98, 0, 99, 0, 100, 0, 101]
----------------------------------------------
[0, 97, 0, 98, 0, 99, 0, 100, 0, 101]
----------------------------------------------
[97, 0, 98, 0, 99, 0, 100, 0, 101, 0]
*************************************************************************************************************************
代碼段二:
ByteBuffer buf = ByteBuffer.wrap(new byte[10]);
buf.asCharBuffer().put("abcde");
System.out.println(Arrays.toString(buf.array()));
System.out.println("----------------------------------------------");
buf.rewind();
buf.order(ByteOrder.BIG_ENDIAN);
buf.asCharBuffer().put("abcde");
System.out.println(Arrays.toString(buf.array()));
System.out.println("----------------------------------------------");
buf.rewind();
buf.order(ByteOrder.LITTLE_ENDIAN);
//buf.asCharBuffer().put("abcde");
System.out.println(Arrays.toString(buf.array()));
打印結果:
[0, 97, 0, 98, 0, 99, 0, 100, 0, 101]
----------------------------------------------
[0, 97, 0, 98, 0, 99, 0, 100, 0, 101]
----------------------------------------------
[0, 97, 0, 98, 0, 99, 0, 100, 0, 101]
***********************************************************************************************************************
代碼段三:
ByteBuffer buf = ByteBuffer.wrap(new byte[10]);
buf.asCharBuffer().put("abcde");
System.out.println(Arrays.toString(buf.array()));
System.out.println("----------------------------------------------");
buf.rewind();
buf.order(ByteOrder.BIG_ENDIAN);
buf.asCharBuffer().put("abcde");
System.out.println(Arrays.toString(buf.array()));
System.out.println("----------------------------------------------");
buf.rewind();
buf.asCharBuffer().put("abcde");
buf.order(ByteOrder.LITTLE_ENDIAN);
System.out.println(Arrays.toString(buf.array()));
打印結果:
[0, 97, 0, 98, 0, 99, 0, 100, 0, 101]
----------------------------------------------
[0, 97, 0, 98, 0, 99, 0, 100, 0, 101]
----------------------------------------------
[0, 97, 0, 98, 0, 99, 0, 100, 0, 101]
ByteBuffer
order(ByteOrder bo)
修改此緩衝區的字節順序。
當我們調用這一方法時,必須首先用order(ByteOrder bo)方法設置字節的排放次序,然後再向緩衝中存入相應的值,這個時候才能得到我們想要的結果(字節的存放順序是根據CPU的不同而不同)。
代碼段四:
public static void long2Byte(long num) {
ByteBuffer buf = ByteBuffer.wrap(new byte[8]);
buf.asLongBuffer().put(num);
System.out.println("默認的字節存放順序:"+Arrays.toString(buf.array()) +"\n當前字節存放方式:"+buf.order());
buf.order(ByteOrder.LITTLE_ENDIAN);
buf.asLongBuffer().put(num);
System.out.println("改後的字節存放順序:"+Arrays.toString(buf.array()) +"\n改後字節存放方式:"+buf.order());
}
打印結果:傳入參數為:8L
默認的字節存放順序:[0, 0, 0, 0, 0, 0, 0, 126]
當前字節存放方式:BIG_ENDIAN
改後的字節存放順序:[126, 0, 0, 0, 0, 0, 0, 0]
改後字節存放方式:LITTLE_ENDIAN
******************************************************************************************************************************
代碼段五:
public static void long2Byte(long num) {
ByteBuffer buf = ByteBuffer.wrap(new byte[8]);
buf.asLongBuffer().put(num);
System.out.println("默認的字節存放順序:"+Arrays.toString(buf.array()) +"\n當前字節存放方式:"+buf.order());
buf.asLongBuffer().put(num);
buf.order(ByteOrder.LITTLE_ENDIAN);
System.out.println("改後的字節存放順序:"+Arrays.toString(buf.array()) +"\n改後字節存放方式:"+buf.order());
}
打印結果:傳入參數為:8L
默認的字節存放順序:[0, 0, 0, 0, 0, 0, 0, 126]當前字節存放方式:BIG_ENDIAN
改後的字節存放順序:[0, 0, 0, 0, 0, 0, 0, 126]
改後字節存放方式:LITTLE_ENDIAN
代碼段六:
/*
* long 與byte[]之間的轉換
*/
public static byte[] long2Byte(long num) {
ByteBuffer buf = ByteBuffer.wrap(new byte[8]);
buf.asLongBuffer().put(num);
System.out.println("默認的字節存放順序:"+Arrays.toString(buf.array()) +"\n當前字節存放方式:"+buf.order());
buf.rewind();
buf.order(ByteOrder.LITTLE_ENDIAN);
buf.asLongBuffer().put(num);
System.out.println("改後的字節存放順序:"+Arrays.toString(buf.array()) +"\n改後字節存放方式:"+buf.order());
byte[] array = Arrays.copyOfRange(buf.array(), 0, 2);//將當前8字節數組截取位2個字節長度
return array;
}
public static long byte2Long(byte[] b) {
byte[] copyOf = Arrays.copyOf(b, 8); //將2個字節長度的數組還原成8個長度的數組
ByteBuffer buf = ByteBuffer.wrap(copyOf);
System.out.println("默認的字節存放順序:"+Arrays.toString(buf.array()) +"\n當前字節存放方式:"+buf.order());
buf.order(ByteOrder.LITTLE_ENDIAN);
System.out.println("改後的字節存放順序:"+Arrays.toString(buf.array()) +"\n改後字節存放方式:"+buf.order());
return buf.asLongBuffer().get();
}
測試:
public static void main(String[] args) {
byte[] b = ConvertUtils.long2Byte(126);
System.out.println(Arrays.toString(b));
long l = ConvertUtils.byte2Long(b);
System.out.println(l);
}
打印結果:
默認的字節存放順序:[0, 0, 0, 0, 0, 0, 0, 126]
當前字節存放方式:BIG_ENDIAN
改後的字節存放順序:[126, 0, 0, 0, 0, 0, 0, 0]
改後字節存放方式:LITTLE_ENDIAN
[126, 0]
默認的字節存放順序:[126, 0, 0, 0, 0, 0, 0, 0]
當前字節存放方式:BIG_ENDIAN
改後的字節存放順序:[126, 0, 0, 0, 0, 0, 0, 0]
改後字節存放方式:LITTLE_ENDIAN
126
以上測試表明:
1.我們對一個小於2個字節長度的long型數字傳入,再通過byte2Long()方法返回出剛才輸入的數字,這種方式較常用於對於網絡信息的編碼解碼。
如果不明白為什麼傳入的是2個字節長度的long型數字,那麼就可以將紅色部分代碼注釋掉,將藍色的copyOf換成傳入的字節數組b,那麼上述代碼就是對一個long型數字的高位和地位存放順序的調換的工具類。因本人當前為高位存儲,所以將其轉成了低位存放方式。最後再將其轉換為高位得到原始輸入的數據。
2.我們關注一下綠色的打印內容,會發現我們明明已經對輸入的字節數組進行了低位轉換,可是輸出時發現沒有任何變化,由此得知:
ByteBuffer 的order(ByteOrder.LITTLE_ENDIAN);這個方法隻對非字節數組類型的變量有效。因為我們直接操作字節數組的時候,無論CPU如何存放,我們已經手動規定死了字節的存放順序。所以這一方法無影響。
最後更新:2017-04-02 06:51:55