Java
的二进制文件字节序转换
烤鱼片
(@eii.dlmu)
字节序指的是数据存储的顺序问题,分为Big-Endian和Little-Endian,Big-Endian指的是数据中的高位存储在存储器的低位,Little-Endian正好相反。Big-Endian也叫大头在前,Little-Endian叫做小头在前。
举例而言,有一个4字节的数据0x01020304,要存储在内存中或文件中编号0~3字节的位置,两种字节序的排列方式分别如下:
Big Endian
低地址
高地址
----------------------------------------->
地址编号
|
0 | 1 | 2 | 3 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
01 | 02 | 03 | 04 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Little Endian
低地址
高地址
----------------------------------------->
地址编号
|
0 | 1 | 2 | 3 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
04 | 03 | 02 | 01 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
如果按照我们一般的书写习惯来说,Big-Endian似乎更好一点。
具体应用中是用big还是little就要取决于系统平台了。不同的CPU会有不同的情况,比如说x86架构的cpu使用的是little模式,而PowerPC则是big。C/C++语言对数据的处理取决于其运行的CPU,而Java则统一使用big模式。
如果单纯仅是使用Java的话也就不存在大小字节序的处理问题,但有时候Java程序可能还要使用到C/C++这类语言生成的数据,尤其是在我们常用x86环境下,两种语言的字节序就会出现不一致的问题,必须做一定的处理。
处理的方法很简单,就是把数据按字节前后调换一下就可以了。
在这里是将长度为len的数据转换成字节数组str[len],带入以下函数,如果原始数据是little,也就是big=false的情况下,函数将对数据进行高低位的调换,并返回。
public
static
byte
[] ReversEndian(
byte
str[],
int
len,
boolean
big)
{
byte
b;
byte
res[]=
new
byte
[len];
for
(
int
i=0;i<len;i++)
{
res[i]=str[i];
}
if
(big==
false
)
{
for
(
int
i=0;i<len;i++)
{
b=str[i];
res[len-i-1]=b;
}
}
return
res;
}
假设现在我们需要从一个C/C++语言生成的二进制文件中读出一个float数据,可以如下处理。
//
文件名
String fileName=
"file"
;
//float
变量是
4
字节长
byte
b[]=
new
byte
[4];
ByteBuffer bb;
File file=
new
File(fileName);
FileInputStream fis=
new
FileInputStream(file);
//
从文件中读取一个
4
字节数据
fis.read(b);
//
反转
b=ReversEndian(b,4,
false
);
//
将字节数组还原成浮点数值
bb=ByteBuffer.wrap(b);
float value=bb.getFloat();