如何将C风格二进制浮点数组读入Java?
我有一个二进制文件,里面存储了8字节的浮点数(双精度浮点数)。当我用下面的代码在Python中读取这个文件时:
import array
d = array.array('d')
d.fromfile(open("foo", mode="rb"), 10)
print d
我得到的结果和用Java在同一个文件上运行的代码得到的结果不一样:
DataInputStream is;
try {
is = new DataInputStream(new FileInputStream(FILE_NAME));
int n = 0;
while(n < 10) {
System.out.println(is.readDouble());
n++;
}
is.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
我哪里出错了呢?
以下是示例输出:
Java:
-6.519670308091451E91
-6.723367689137016E91
0.0
-6.519664091503568E91
1.2029778888642203E-19
1.2029778888642203E-19
1.2028455399662426E-19
-1.1421078747242632E217
2.2734939098318505E236
-3.494281168153119E125
Python:
array('d', [-1.504936576164858e-36, -5.878658489696332e-39, 0.0, -5.878658478748688e-39, 5.878658495170291e-39, 5.878658495170291e-39, -5.878655692573363e-39, -5.87865851296011e-39, 4.79728723e-315, 1.546036714e-314])
这是我用来生成数据的C程序:
#include <stdio.h>
double test_data[10] = {
-1.504936576164858e-36,
-5.878658489696332e-39,
0.0,
-5.878658478748688e-39,
5.878658495170291e-39,
.878658495170291e-39,
-5.878655692573363e-39,
-5.87865851296011e-39,
4.79728723e-315,
1.546036714e-314
};
int main() {
FILE * fp;
fp = fopen("foo", "wb");
if(fp != NULL) {
fwrite(test_data, sizeof(double), 10, fp);
fclose(fp);
}
return 0;
}
2 个回答
1
Java在读取doubles
时是按照大端格式来处理的,而你的数据可能是小端格式。要在Java中读取小端格式的双精度浮点数,你可以使用:
double d = Double.longBitsToDouble(Long.reverseBytes(is.readLong()));
这个方法会从文件中读取八个字节,把字节的顺序从一种格式转换成另一种格式,然后再把这个值转换成double
类型。
3
Java的 DataInputStream
总是把数据当作大端格式来处理。你可以用Python的 struct
模块 来查看这个,结合你的示例数据:
>>> s = struct.pack("<d", -1.504936576164858e-36)
>>> s
'\xd3\x00\x00\xb9\xd3\x00\x80\xb8'
>>> struct.unpack("<d", s)
(-1.504936576164858e-36,)
>>> struct.unpack(">d", s)
(-6.519670308091451e+91,)
你需要弄清楚的问题是,你看到的数据是以小端格式还是大端格式存储的,然后正确地理解它。