什么是大端、小端?
字节是计算机中数据处理的基本单位。
计算机中以字节为单位存储和解释信息,规定一个字节由八个二进制位构成,即1个字节等于8个比特(1Byte=8bit)。
计算机进行数据处理时,一次存取、加工和传送的数据长度称为字(word)。一个字通常由一个或多个(一般是字节的整数位)字节构成。
但并非所有计算机都以相同的顺序存储由多字节值组成的字节。考虑一个由2个字节组成的16位因特网。存储该值有两种方式
- Little Endian 小端: 低阶字节存储在起始地址(A),高阶字节存储在下一个地址(A + 1)
- Big Endian 大端:高阶字节存储在起始地址(A),低阶字节存储在下一个地址(A + 1)
网络字节顺序: 为了允许具有不同字节顺序约定的计算机相互通信,Internet协议为在网络上传输的数据指定了规范的字节顺序约定。
network order 即网络序,默认网络传输字节为大端
小端和大端是存储多字节数据类型(int、float等)的两种方式
- 计算机内存由正整数地址引用。在计算机内存中,把最低有效字节放在最高有效字节之前存储数字是“自然的”。
“自然”顺序,即在内存中较低有效字节出现在较高有效字节之前。自然顺序是采用小端方式存储- 基于英特尔的处理器是小端。ARM处理器是小端处理器。
- 但许多供应商,如IBM、CRAY和Sun,更喜欢采用相反的顺序存储数据,即采用大端方式存储。
- 双端处理器可以在小端和大端两种模式下运行。当前的一代ARM处理器是双端处理器。
根据这些定义,一种32位数据模式,它被视为32位无符号整数。“高阶”字节是2的最大次方:231,…, 224。“低阶”字节是2的最小次方: 27,…, 20。
示例如下:
- MSB:全称为Most Significant Bit,在二进制数中属于最高有效位,MSB是最高加权位,与十进制数字中最左边的一位类似。
- LSB:全称为Least Significant Bit,在二进制数中意为最低有效位,
一般来说,MSB位于二进制数的最左侧,LSB位于二进制数的最右侧。
字节顺序是否影响文件格式?
- 以1字节为基本单位的文件格式独立于字节顺序,例如ASCII文件。
- 其他文件格式使用一些固定的端顺序格式,例如JPEG文件以大端顺序格式存储。
- java 全部为大端(与平台无关): Java二进制文件中的所有内容都以大端顺序存储。这意味着如果您只使用Java,那么所有文件在所有平台(Mac、PC、UNIX等)上的处理方式都是相同的。
- C语言默认是小端模式:用C语言编写的程序通常使用 小端顺序
如何知道机器的字节次序
How to Know the Endian-ness?
在Java中,我们可以使用ByteOrder.nativeOrder()方法来获取CPU使用的字节顺序。在使用Intel CPU 或 AMD CPU时,输出结果都是小端顺序
ByteOrder byteOrder = ByteOrder.nativeOrder();
System.out.println(byteOrder); //LITTLE_ENDIAN
如何进行大小端的转换
在java中,可以基于ByteBuffer提供的order方法,进行大小端的转换
如处理网络字节流时,先针对获取的byte[] 进行 buffer.order(ByteOrder.BIG_ENDIAN);
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
public class SimpleDemo {
public static void main(String[] args) throws UnsupportedEncodingException {
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(10);
byteBuffer.put("Test".getBytes(StandardCharsets.UTF_8));
byteBuffer.flip();
System.out.println(Arrays.toString(convert(byteBuffer, ByteOrder.BIG_ENDIAN)));
byteBuffer.flip();
System.out.println(Arrays.toString(convert(byteBuffer, ByteOrder.LITTLE_ENDIAN)));
}
/**
* 必须调用完后flip()才可以调用此方法
* @param byteBuffer
* @param bo
* @return
*/
public static byte[] convert(ByteBuffer byteBuffer, ByteOrder bo) {
byteBuffer.order(bo);
int len = byteBuffer.limit() - byteBuffer.position();
byte[] bytes = new byte[len];
if (byteBuffer.isReadOnly()) {
return null;
} else {
byteBuffer.get(bytes);
}
return bytes;
}
}