Java 范例 - 字节处理

前言

Java 编程中常会遇到须要进行字节处理的地方,本篇文章就来探讨编程中会遇到的字节处理问题。编程

字节序

字节序(endianness)是对于多字节数据来讲的,它描述了多字节数据存储的顺序,分为大端字节序(big endian)和小端字节序(little endian)两种。数组

大端序即高位字节位于低地址,而小端字节序则与之相反。例如 4 字节的数据 0x01234567,其 大、小端字节序存储顺序以下。网络

Big Endian编码

address |0x100|0x101|0x102|0x103|
content |01   |23   |45   |67   |

Little Endiancode

address |0x100|0x101|0x102|0x103|
content |67   |45   |23   |01   |

为保证数据在不一样设备进行传输时能被正确解析,规定了使用大端字节序做为网络字节序orm

字节序转换

因为 Java 使用大端字节序在内存中进行数据存储,因此进行网络传输时不须要进行字节序转换。不过除了网络编程,仍是有须要小端字节序的状况,下面就来讨论如何进行字节序的转换。内存

基本类型字节数

下表给出了 Java 八种基本类型的所占的字节数,能够看到里面六种类型都是多字节的,而这六种在转换时都是须要处理的。ci

类型 字节数
byte 1
boolean 1
char 2
short 2
int 4
float 4
long 8
double 8

这里须要强调一点,基本类型的数组形式虽是多字节的,但其字节序只和数组元素有关,而与数组元素的顺序无关。例如存在短整形数组 {0x0001, 0x0002} (Java 默认的大端字节序),则其小端字节序是 {0x0100, 0x0200}字符串

字节缓冲区

字节缓冲区(ByteBuffer)经常使用于数据的字节级处理,能够利用静态方法 ByteBuffer allocate(int) 来申请一块固定大小的缓冲区,或者使用 ByteBuffer wrap(byte[]) 包装一个现有的字节数组。get

字节缓冲区提供了 void order(ByteOrder) 方法来设置该字节缓冲区的字节序,提供了 asTypeBuffer() (其中 Type 为多字节的基本类型)来将字节缓冲区做为其余基本类型缓冲区,以便于插入其余基本类型,利用这些特性即可实现基本类型的字节序转换。

基本类型及其数组的字节序转换

下面例子利用了字节缓冲区来进行整型的字节序转换,而只需将 asIntBuffer() 改为相应基本类型的 asTypeBuffer() 方法,就能够进行其它基本类型的字节序转换。

int data = 0x01020304;
ByteBuffer buf = ByteBuffer.allocate(Integer.BYTES);

buf.asIntBuffer().put(data);
// [1, 2, 3, 4]
System.out.println(Arrays.toString(buf.array()));

buf.order(ByteOrder.LITTLE_ENDIAN);
buf.asIntBuffer().put(data);
// [4, 3, 2, 1]
System.out.println(Arrays.toString(buf.array()));

对于基本类型的数组,只需将 data 数据改为数组便可,以下面给出的例子。

int[] data = new int[]{0x01020304, 0x05060708};
ByteBuffer buf = ByteBuffer.allocate(Integer.BYTES * data.length);

buf.asIntBuffer().put(data);
// [1, 2, 3, 4, 5, 6, 7, 8]
System.out.println(Arrays.toString(buf.array()));

buf.order(ByteOrder.LITTLE_ENDIAN);
buf.asIntBuffer().put(data);
// [4, 3, 2, 1, 8, 7, 6, 5]
System.out.println(Arrays.toString(buf.array()));

字符串的字节序转换

Java 中字符类型使用 Unicode 字符集,因此占用两个字节,而字符串只须要将其转成字符数组便可进行字节序转换。

char[] data = new String("example").toCharArray();
ByteBuffer buf = ByteBuffer.allocate(Character.BYTES * data.length);
buf.order(ByteOrder.LITTLE_ENDIAN);
buf.asCharBuffer().put(data);

字符串编码与字节数组

编程中一般须要将字符串转字节数组,而这就涉及到字符串编解码,但 Java 提供了很便捷的方式来进行转换,因此无需关心如何字符串编解码。

byte[] buf = new String("example").getBytes();  // use platform's default charset

注意上面使用了平台的默认的字符集(可利用 Charset.defaultCharset() 获取平台默认字符集)进行解码,而不是上面提到的 Unicode 字符集,但能够以下面例子同样指定字符集。

byte[] buf = new String("example").getBytes("UTF-8");  // use specify charset 'UTF-8'