Pythonでバイナリファイルを読み取る


104

Pythonでのバイナリファイルの読み取りは特に難しいと思います。手伝って頂けますか?このファイルを読む必要があります。このファイルはFortran 90では簡単に読むことができます。

int*4 n_particles, n_groups
real*4 group_id(n_particles)
read (*) n_particles, n_groups
read (*) (group_id(j),j=1,n_particles)

詳細には、ファイル形式は次のとおりです。

Bytes 1-4 -- The integer 8.
Bytes 5-8 -- The number of particles, N.
Bytes 9-12 -- The number of groups.
Bytes 13-16 -- The integer 8.
Bytes 17-20 -- The integer 4*N.
Next many bytes -- The group ID numbers for all the particles.
Last 4 bytes -- The integer 4*N. 

これをPythonでどのように読むことができますか?私はすべてを試しましたが、うまくいきませんでした。Pythonでf90プログラムを使用して、このバイナリファイルを読み取り、使用する必要のあるデータを保存する可能性はありますか?


1
このファイルはFortranプログラムによって作成されたものですか?その場合、どのように書き込まれたか。Fortranはデフォルトで、ファイルに書き込む各レコードの前に追加のデータを追加するためです。データを読み取るときは、これに注意する必要があります。
Chris

1
私の以前のコメントは無視してください。整数8と4 * Nは明らかにこの追加データです。
Chris

2
また、Pythonでのバイナリファイルの読み取りに関する質問への回答もご覧ください。
Chris

Numpyのfromfile関数を使用すると、バイナリファイルを簡単に読み取ることができます。私はそれをお勧めします。
littleO

...そして常にエンディアンネスに注意してください。異なるメーカーのコンピューター間で移植する場合。
DragonLord

回答:


153

次のようなバイナリファイルの内容を読み取ります。

with open(fileName, mode='rb') as file: # b is important -> binary
    fileContent = file.read()

次にstruct.unpackを使用してバイナリデータを「アンパック」します

開始バイト: struct.unpack("iiiii", fileContent[:20])

本文:見出しバイトと末尾バイト(= 24)を無視します。残りの部分は本体を形成し、本体のバイト数を知るために4で整数除算を行います。取得した商に文字列'i'を掛けて、unpackメソッドの正しい形式を作成します。

struct.unpack("i" * ((len(fileContent) -24) // 4), fileContent[20:-4])

終了バイト: struct.unpack("i", fileContent[-4:])


この他の投稿を見ていただけますか?stackoverflow.com/questions/8092469/… ...別のバイナリファイルをもう一度読みますが、この場合、バイト構造の詳細はわかりません。たとえば、整数8が存在する場合があることを理解しました。ただし、IDLを使用すると、このデータを読み取るのが非常に簡単になります。Pythonでも同じことができますか?
Brian

投稿された回答やコメントに満足できない理由を(ここではなく、他の投稿の中に)示してください。おそらく、質問を更新して詳細を提供する必要があるかもしれません...更新されたときに確認します。
gecco 2012年

アンパックされたchar []を文字列に変換する必要がある場合は、この回答を参照してください。
PeterM 2016年

import struct
JW

23

一般的には、Pythonのstructモジュールを使用することを検討することをお勧めします。Pythonの標準であり、質問の仕様をに適したフォーマット文字列に簡単に変換できるはずですstruct.unpack()

フィールド間またはフィールドの周りに「見えない」パディングがある場合は、それを理解してunpack()呼び出しに含める必要があります。そうしないと、間違ったビットが読み取られます。

何かをアンパックするためにファイルの内容を読み取るのは非常に簡単です。

import struct

data = open("from_fortran.bin", "rb").read()

(eight, N) = struct.unpack("@II", data)

これは、最初の2つのフィールドをアンパックします。フィールドがファイルの先頭から始まると想定し(パディングや無関係なデータはありません)、ネイティブのバイト順(@シンボル)も想定します。I書式文字列内のS「は、32ビット符号なし整数」を意味します。


わかりましたが、ファイルのバイトを読み取る方法もわかりません。私の質問から、ファイルをバイト5から8から読み取り、結果を整数に変換するにはどうすればよいですか?すみませんが、Pythonは初めてです。
Brian

14

numpy.fromfileテキストファイルとバイナリファイルの両方からデータを読み取ることができるを使用できます。まず、を使用してファイル形式を表すデータ型を作成しnumpy.dtype、次にを使用してファイルからこの型を読み取りますnumpy.fromfile


2
これを見逃しやすい!ドキュメントは少し薄いです。参照reddit.com/r/Python/comments/19q8nt/...を議論するために
失われた

11

バイナリファイルをbytesオブジェクトに読み込むには:

from pathlib import Path
data = Path('/path/to/file').read_bytes()  # Python 3.5+

intデータのバイト0から3 を作成するには:

i = int.from_bytes(data[:4], byteorder='little', signed=False)

intデータから複数のをアンパックするには:

import struct
ints = struct.unpack('iiii', data[:16])

0

バイナリファイルの読み取りと書き込みに関しては、Pythonにも欠けているので、小さなモジュール(Python 3.6以降用)を作成しました。

ではbinaryfileあなたは(私は、Fortranを知らないので、私は、推測している)、このような何かをしたいです:

import binaryfile

def particle_file(f):
    f.array('group_ids')  # Declare group_ids to be an array (so we can use it in a loop)
    f.skip(4)  # Bytes 1-4
    num_particles = f.count('num_particles', 'group_ids', 4)  # Bytes 5-8
    f.int('num_groups', 4)  # Bytes 9-12
    f.skip(8)  # Bytes 13-20
    for i in range(num_particles):
        f.struct('group_ids', '>f')  # 4 bytes x num_particles
    f.skip(4)

with open('myfile.bin', 'rb') as fh:
    result = binaryfile.read(fh, particle_file)
print(result)

これは次のような出力を生成します:

{
    'group_ids': [(1.0,), (0.0,), (2.0,), (0.0,), (1.0,)],
    '__skipped': [b'\x00\x00\x00\x08', b'\x00\x00\x00\x08\x00\x00\x00\x14', b'\x00\x00\x00\x14'],
    'num_particles': 5,
    'num_groups': 3
}

私はskip()を使用してFortranが追加する追加データをスキップしましたが、代わりにFortranレコードを適切に処理するためのユーティリティを追加したい場合があります。もしそうなら、プルリクエストは歓迎されます。


-2
import pickle
f=open("filename.dat","rb")
try:
    while True:
        x=pickle.load(f)
        print x
except EOFError:
    pass
f.close()

6
これが他の回答よりも優れている(または少なくとも同等以上の)理由について、ほんの少し説明するだけの価値があります。
Phil

2
あなたはこれがfortranで生成されたバイナリで動作することを確認しましたか?
agentp 2017

1
そして、それが何をするかを説明します...ピクルスとは何ですか?何がpickle.loadロードされますか?Fortranストリーム、直接ファイルまたは順次ファイルをロードしますか?それらは異なり、互換性がありません。
ウラジミールF
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.