2016-04-01 22 views
0

私はC言語でバイナリ形式でファイルを書きました。私が使用しているフォーマットは以下の通りである:5倍(40バイトの合計)とバイナリデータをCのヘッダでPythonで読む

ヘッダ:

fwrite(&FirstNum, sizeof(double), 1, outFile); 
fwrite(&SecNum, sizeof(double), 1, outFile); 
fwrite(&ThirdNum, sizeof(double), 1, outFile); 
fwrite(&FourthNum, sizeof(double), 1, outFile);   
fwrite(&FifthNum, sizeof(double), 1, outFile); 

そしてIは、256^3 "粒子" 上cicleに対して行います。各粒子についてI 9つの値を書き込む:最初のものは整数であり、他方8は、以下のように、倍精度である:GPは私の粒子の情報を含むだけのデータ構造である

Ntot = 256*256*256 
for(i=0; i<Ntot; i++) 
    { 
    fwrite(&gp[i].GID, sizeof(int), 1, outFile); 

    /*----- Positions -----*/ 
    pos_aux[X] = gp[i].pos[X]; 
    pos_aux[Y] = gp[i].pos[Y]; 
    pos_aux[Z] = gp[i].pos[Z]; 

    fwrite(&pos_aux[0], sizeof(double), 3, outFile); //Positions in 3D 
    fwrite(&gp[i].DenConCell, sizeof(double), 1, outFile); //Density 
    fwrite(&gp[i].poten_r[0], sizeof(double), 1, outFile); //Field 1 
    fwrite(&gp[i].potDot_r[0], sizeof(double), 1, outFile); //Field 2 
    fwrite(&gp[i].potDot_app1[0], sizeof(double), 1, outFile); //Field 3 
    fwrite(&gp[i].potDot_app2[0], sizeof(double), 1, outFile); //Field 4 
    } 

。次に、256^3パーティクルのそれぞれについて、私は合計68バイトを使用しました:ダブルスのint + 8 *(8バイト)のために4バイト。

私が必要とするのは、そのような形式を読むのですが、いくつかのプロットを作るためには、Pythonで読むのですが、私は少しPythonを使っています。私はPythonでバイナリ形式のファイルを読む答えをいくつか読んだが、私は自分のヘッダを読むことができただけで、 "body"やその他の粒子に関する情報は読み取れなかった。私がしようとしたことは、次のとおりです。

Npart = 256 
with open("./path/to/my/binary/file.bin", 'rb') as bdata: 
    header_size = 40 # in bytes   
    bheader = bdata.read(40) 
    header_data = struct.unpack('ddddd', bheader) 
    FirstNum = header_data[0] 
    SecNum = header_data[1] 
    ThirdNum = header_data[2] 
    FourthNum = header_data[3] 
    FifthNum = header_data[4] 
    #Until here, if I print each number, I obtain the correct values. 
    #From here, is what I've tried in order to read the 9 data of the 
    #particles 
    bytes_per_part = 68 
    body_size = int((Npart**3) * bytes_per_part) 
    body_data_read = bdata.read(body_size) 
    #body_data = struct.unpack_from('idddddddd', bdata, offset=40) 
    #body_data = struct.unpack('=i 8d', body_data_read) 
    body_data = struct.unpack('<i 8d', body_data_read) 

    #+++++ Unpacking data ++++++ 
    ID_us = body_data[0] 
    pos_x_us = body_data[1] 
    pos_y_us = body_data[2] 
    pos_z_us = body_data[3] 
    DenCon_us = body_data[4] 

しかし、私は自分のコードを実行すると、私はこのエラーを取得:

body_data = struct.unpack('<i 8d', body_data_read) 
struct.error: unpack requires a string argument of length 68 

私が最初のコメント行で試してみました:

#body_data = struct.unpack_from('idddddddd', bdata, offset=40) 

しかし、エラーは言う:

struct.error: unpack requires a string argument of length 72 

私は私が最初に示したエラー得るラインに

body_data = struct.unpack('=i 8d', body_data_read) 

またはライン

body_data = struct.unpack('<i 8d', body_data_read) 

を使用する場合:

struct.error: unpack requires a string argument of length 68 

を実際に私は全く理解していないように、私は感じます文字列の文字「=」と「<」です。なぜなら、それらの文字を読み込む必要があると思われる長さを得るためですが、私は読むことができません。私が最終的に必要とするのは、pos_y_usにはpos_x_us、pos_y_usにはpos_x_us、posにはpos_z_us、zにはposの位置などがあります。あなたが私に必要なものを得る方法について私にいくつかのアイデアや啓発を与えることができれば感謝します。

+1

'struct.unpack_from( '=' +(Npart ** 3)* 'i8d'、body_data_read)'は動作しますか?一度にすべてのデータを読み込み、その後9つの値ごとに分割することができます – Reti43

+0

ありがとうございます。作品のように見えますが、同じエラーはありませんが、 'pos_x_us = body_data [1] 'で示したように分割しようとすると、完全な配列ではなくpos_x_usに1つの数字だけが割り当てられます。どうしたらいいですか? – Darivadi

+0

うん、 'body_data [1]'はリストの2番目の位置の値だけをフェッチします。すべてのx値が必要な場合は、スライス:body_data [1 :: 9]を使用します。 – Reti43

答えて

1

バッファサイズがフォーマットに一致しなかったため、問題が発生しました。ランダムなデータで試してみましょう。全体的に12バイトで、intとfloatを対象としています。あなたが使用していない場合は

>>> data = '\xf4\x9f\x97\xcd\xf2\xbe\xd6\x87\x18\xe3\x17\xdf' 

'<'、 '>'、 '='、および '!'、paddingがあるでしょう。

Padding is only automatically added between successive structure members. No padding is added at the beginning or the end of the encoded struct.

>>> struct.unpack('id', data) 

Traceback (most recent call last): 
    File "<pyshell#56>", line 1, in <module> 
    struct.unpack('id', data) 
error: unpack requires a string argument of length 16 

しかし

>>> struct.unpack('=id', data) 
(-845701132, -1.2217466572589222e+150) 

具体的には、 'd' は、独自に8つのバイトを取り、Iは​​4になります。'iii'は同じタイプなので、それ自身で12と同じです。しかし、あなたが 'id'を実行しようとすると、それは好きではなく、整数を8バイトに埋め込みます。 'c'は1バイトを取るが、 'ci'は8が必要です。基本的には、struct.unpack('ddddd')は状況によっては正常に動作しました。

他のエラーは、バッファのサイズと一致しない形式から発生します。 struct.unpack()を使用する場合は正確に一致する必要がありますが、struct.unpack_from()を使用する場合は、少なくともフォーマットのサイズが必要です。 24バイトのデータで試してみましょう。

# this will fetch 12 bytes, even if the stream has more 
>>> struct.unpack_from('=id', 2*data) 
(-845701132, -1.2217466572589222e+150) 

しかし

>>> struct.unpack('=id', 2*data) 

Traceback (most recent call last): 
    File "<pyshell#60>", line 1, in <module> 
    struct.unpack('=id', 2*data) 
error: unpack requires a string argument of length 12 

あなたが今見ることができるように、あなたのデータはあなたのフォーマットに必要な、それを一致させるためには、実際に

body_size = int((Npart**3) * bytes_per_part) 
body_data_read = bdata.read(body_size) 

た 'i8di8di8dを...' Npart **3回。だから、

body_data = struct.unpack('='+(Npart**3)*'i8d', body_data_read) 

は今、あなたは一度、すべてのデータで読んだことがあると、あなたが望むようにそれらを分割を開始することができます。たとえば、2番目の値は最初のパーティクルのx座標を持ち、このパターンは9個の値を繰り返すため、スライスしたすべてのパーティクルのx座標を取得できます。

pos_x_us = body_data[1::9] 
+0

もう一度、ありがとう!あなたは非常に明確で助かりました。それは完璧に働いた。 – Darivadi