我有简单的C和Java代码,可以从非文本文件中读取整数。当我以十六进制打印结果时,Java代码的字节顺序似乎与C代码不同。示例:
int fd = open("MyFile", O_RDONLY);
int rc = read(fd, &MagicNumber, 4);
printf("MagicNumber is 0x%xn", MagicNumber);
此打印:MagicNumber为0xff017ffe
Java代码是:
FileInputStream fin = new FileInputStream("MyFile");
DataInputStream din = new DataInputStream(fin);
int MagicNumber = din.readInt();
System.out.printf("MagicNumber is 0x%xn", MagicNumber);
它打印:MagicNumber是0xfe7f01ff
输出是相似的,但字节是交换的。我是否错误地执行了文件I/O?我需要做些什么来在C和Java之间一致地读取字节吗?
DataInputStream
中的字节顺序是"big-endian"(也称为"网络顺序"(。这几乎被所有二进制网络协议和许多文件格式所使用,尽管小端结构现在占主导地位。
在C代码中,您可以使用ntohl
将"网络顺序"转换回"主机顺序",而无需知道主机顺序是小端序还是大端序。
#include <arpa/inet.h>
...
printf("MagicNumber is 0x%xn", ntohl(MagicNumber));
DataInputStream
使用big-endian字节顺序读取多字节值,将最高有效字节放在第一位,将最低有效字节放最后。
正如维基百科所说:
大端序是网络协议(IP、TCP、UDP(中的主要顺序。相反,小端序是处理器体系结构(x86、大多数ARM实现、基本RISC-V实现(及其相关内存的主要顺序。文件格式可以使用任意一种排序;有些格式混合使用两者。
由于DataInputStream
用于数据交换,因此它使用"网络顺序",也就是big-endian。
要控制字节顺序,应该使用ByteBuffer
。这里有一个简单的例子。
FileInputStream fin = new FileInputStream("MyFile");
byte[] buffer = fin.readNBytes(Integer.BYTES);
int magicNumber = ByteBuffer.wrap(buffer).order(ByteOrder.LITTLE_ENDIAN).getInt();