大量の浮動小数点数のデータをJavaからバイナリ出力してPythonで読み込む

Javaで処理して作成した大量の浮動小数点数のデータをバイナリでファイル出力して、それをPythonで読み込む方法を確認しました。

Javaからは DataOutputStream で書き出し、Pythonでは struct.unpack メソッドで読み込みます。

JavaDataOutputStream はハードウェアのバイトオーダーに依存せず、ビッグエンディアンで処理することになっています。従って、Pythonでの読み込み時もビッグエンディアンで読み込むことになります。

前回の記事にも似たことを書いてます。

書き出し側サンプルコード

sample1.java

import java.io.BufferedOutputStream;
import java.io.DataOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;

class Main {
  public static void main(String[] args) throws IOException {
    // 適当な12個の浮動小数点数を作成
    double[] arr = new double[12];
    for (int i = 0; i < arr.length; i++) {
      double th = Math.PI / 6 * i;
      double x = Math.sin(th);
      arr[i] = x;

      // 確認のため標準出力
      System.out.printf("%f\n", x);
    }

    // 倍精度浮動小数点数をビッグエンディアンでファイルに書き出し
    var dataFilePath = "data.dat";
    var output = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(dataFilePath)));
    for (int i = 0; i < arr.length; i++) {
      output.writeDouble(arr[i]);
    }
    output.close();
  }
}

実行します。

$ java sample1.java
0.000000
0.500000
0.866025
1.000000
0.866025
0.500000
0.000000
-0.500000
-0.866025
-1.000000
-0.866025
-0.500000

data.dat が生成されます。サイズを確認すると96バイト。倍精度浮動小数点数は8バイトでそれが12個ですので、あってます。

$ wc -c data.dat
96 data.dat

読み込み側サンプルコード

sample2.py

import struct

f = open('data.dat', 'rb')
binary = f.read(96)
f.close()

lst = struct.unpack('>12d', binary)
# >  : ビッグエンディアン
# 12 : 12個連続して読み込む
# d  : 倍精度浮動小数点数
# 参考
# struct --- バイト列をパックされたバイナリデータとして解釈する — Python 3.9.1 ドキュメント
# https://docs.python.org/ja/3/library/struct.html

for i in range(12):
  print(lst[i])

実行します。

$ python sample2.py
0.0
0.49999999999999994
0.8660254037844386
1.0
0.8660254037844387
0.5000000000000003
1.2246467991473532e-16
-0.4999999999999997
-0.8660254037844384
-1.0
-0.866025403784439
-0.5000000000000004

JavaからPythonに受け渡しできていそうです。