如何读取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;
}

Java的DataInputStream总是将数据视为大端字节。您可以使用Python的struct模块和示例数据看到这一点:

>>> s = struct.pack("<d", -1.504936576164858e-36)
>>> s
'xd3x00x00xb9xd3x00x80xb8'
>>> struct.unpack("<d", s)
(-1.504936576164858e-36,)
>>> struct.unpack(">d", s)
(-6.519670308091451e+91,)

您需要回答的问题是您正在查看的数据是以小端序还是大端序存储,并正确解释它

Java读取doubles作为大端序,而您的数据可能是小端序。要在Java中读取小的端序双精度值,可以使用:

double d = Double.longBitsToDouble(Long.reverseBytes(is.readLong()));

这将从文件中读取8个字节作为long,将单个字节的顺序从一个端序交换到另一个端序,然后将值转换为double

最新更新