一、名词解释
首先解释一下大端模式和小端模式。
小端模式,也叫小端存储:
Little-Endian就是低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。
大端模式,也叫大端存储:
Big-Endian就是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。
比如说数字1045037161
大端存储:
DEC:1045037161
低地址-------------------------->高地址
HEX: 0x3E 0x4A 0x00 0x69
BIN:00111110 01001010 00000000 01101001
小端存储:
DEC:1761626686
低地址-------------------------->高地址
HEX: 0x69 0x00 0x4A 0x3E
BIN:01101001 00000000 01001010 00111110
再举个例子,比如数字37
大端存储:
DEC:37
低地址-------------------------->高地址
HEX: 0x00 0x00 0x00 0x25
BIN:00000000 00000000 00000000 00100101
小端存储:
DEC:620756992
低地址-------------------------->高地址
HEX: 0x25 0x00 0x00 0x00
BIN:00100101 00000000 00000000 00000000
一个字节就是8bit,大小端就是一个字节正着存,一个字节反着存。这两种没有那种好还是不好,就是存储模式不同。但是人们熟悉的方式肯定是大端存储,37读出来就是37,如果是小端存储读出来就是620756992,完全不知道是什么了。
计算机存储是按照字节存储的,一个字节是8比特。但是如果数据比较大,一个字节存储不下,就需要多个字节存储。比如0x1122,也就是数字4386,就是占用了两个字节进行存储。那么0x11就是高位字节,0x22就是低位字节。而存储字节变多了之后,存储的可能性也就会变多了。为了保证数据存储和使用不出错,我们必须按照某种规范进行存储数据。比如0x1122,可以按照0x11 0x22的顺序进行存储(即大端存储),也可以按照0x22 0x11的循序进行存储(即小端模式)。这里就解释了上面的大小端定义。在一个独立的系统中,只要选择一个稳定的存储模式就可以保证系统内部不出错。但是如果和外部系统进行数据交换,则需要商定交换协议,如果两个系统存储方式不同,就涉及到大小端转换问题了。
C语言是小端存储,java都是大端存储。所以java要想读C语言生成的二进制文件,就需要大小端转换了。
二、大小端转换方式
大小端转换其实很简单,就是byte数组,把位置倒叙一下就可以了。自己写代码也就是一个循环,如下:
/**
* 切换大小端
*/
public static byte[] changeBytesEndian(byte[] x){
byte[] y = new byte[x.length];
for (int i = 0; i < y.length; i++) {
y[i] = x[y.length - i - 1];
}
return y;
}
不过,比较正统的转换方式是使用ByteBuffer的order方法。
/**
* 将bytes转为大端数据,返回int
* c存储二进制文件是用的小端存储,java都是大端存储,因此需要转换,此方法用于将数据转为大端存储,读出二进制文件
* @param bytes
* @return
*/
private static int bytesToBigEndian(byte[] bytes) {
return ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN).getInt();
}
/**
* 将bytes转为小端数据,返回int
* c存储二进制文件是用的小端存储,java都是大端存储,因此需要转换,此方法用于将数据转为小端存储,写入二进制文件
* @param bytes
* @return
*/
private static int bytesToLittleEndianInt(byte[] bytes){
return ByteBuffer.wrap(bytes).order(ByteOrder.BIG_ENDIAN).getInt();
}
当然,其他数据类型也是支持的。只是输入的bytes要自己按照位数写对,short是2位,int是4位,long是8位......基础知识就不多说了!