16

私は Python を使用するのに非常に慣れておらず、C に非常に慣れていません。

データを含む .dat ファイルを作成する C の関数があります。ファイルを読み取るためにPythonを使用してファイルを開いています。私が読む必要があるものの 1 つは、C 関数で作成され、バイナリで出力された構造体です。私の Python コードでは、構造体を読み取るファイルの適切な行にいます。スタクト ​​アイテムをアイテムごとに解凍しようとしましたが、全体として成功しませんでした。構造体の項目のほとんどは、C コードで「実数」と宣言されていました。私は他の誰かと一緒にこのコードに取り組んでおり、メインのソース コードは彼のもので、変数を「本物」として宣言しています。「.dat」で終わるディレクトリ内のすべてのファイルを読み取りたいため、これをループに入れる必要があります。私が持っているループを開始するには:

for files in os.listdir(path):
  if files.endswith(".dat"):
    part = open(path + files, "rb")
    for line in part:

次に、構造体を含む行の前のすべての行を読み取ります。次に、その行に到達して、次のようにします。

      part_struct = part.readline()
      r = struct.unpack('<d8', part_struct[0])

構造体に格納されている最初のものを読み取ろうとしています。ここのどこかでこの例を見ました。そして、これを試してみると、次のエラーが表示されます。

struct.error: repeat count given without format specifier

私は誰かが私に与えることができるあらゆるヒントを取り入れます。私はこれに数日間立ち往生しており、さまざまなことを試しました。正直なところ、私は struct モジュールを理解していないと思いますが、できる限り読んだことがあります。

ありがとう!

4

5 に答える 5

19

ctypes.Structureまたはを使用struct.Structして、ファイルの形式を指定できます。@perreal の回答で C コードによって生成されたファイルから構造を読み取るには:

"""
struct { double v; int t; char c;};
"""
from ctypes import *

class YourStruct(Structure):
    _fields_ = [('v', c_double),
                ('t', c_int),
                ('c', c_char)]

with open('c_structs.bin', 'rb') as file:
    result = []
    x = YourStruct()
    while file.readinto(x) == sizeof(x):
        result.append((x.v, x.t, x.c))

print(result)
# -> [(12.100000381469727, 17, 's'), (12.100000381469727, 17, 's'), ...]

を参照してくださいio.BufferedIOBase.readinto()。これは Python 3 でサポートされていますが、Python 2.7 ではデフォルトのファイル オブジェクトについて文書化されていません。

struct.Structパディング バイト ( x) を明示的に指定する必要があります。

"""
struct { double v; int t; char c;};
"""
from struct import Struct

x = Struct('dicxxx')
with open('c_structs.bin', 'rb') as file:
    result = []
    while True:
        buf = file.read(x.size)
        if len(buf) != x.size:
            break
        result.append(x.unpack_from(buf))

print(result)

同じ出力が生成されます。

不要なコピーを避けるためArray.from_buffer(mmap_file)に、ファイルから構造体の配列を取得するために使用できます。

import mmap # Unix, Windows
from contextlib import closing

with open('c_structs.bin', 'rb') as file:
    with closing(mmap.mmap(file.fileno(), 0, access=mmap.ACCESS_COPY)) as mm: 
        result = (YourStruct * 3).from_buffer(mm) # without copying
        print("\n".join(map("{0.v} {0.t} {0.c}".format, result)))
于 2013-06-22T00:27:23.753 に答える
0

フォーマット指定子の数字は繰り返し回数を意味しますが、 のように文字の前に置く必要があり'<8d'ます。ただし、構造体の1つの要素を読みたいだけだと言いました。私はあなたがただ欲しいと思います'<d'。読み取るバイト数を 8 に指定しようとしていると思いますが、その必要はありません。dと仮定します。

を使用していることにも気づきましたreadline。バイナリデータを読み取るのは間違っているようです。バイナリデータでランダムに発生する次のキャリッジ リターン/ライン フィードまで読み取ります。あなたがしたいことはread(size)、次のように使用することです:

part_struct = part.read(8)
r = struct.unpack('<d', part_struct)

read実際には、要求したよりも少ないデータが返される可能性があるため、注意が必要です。その場合は繰り返す必要があります。

part_struct = b''
while len(part_struct) < 8:
    data = part.read(8 - len(part_struct))
    if not data: raise IOException("unexpected end of file")
    part_struct += data
r = struct.unpack('<d', part_struct)
于 2013-06-21T22:12:08.333 に答える
0

私は最近同じ問題を抱えていたので、ここに保存されたタスク用のモジュールを作成しました:http://pastebin.com/XJyZMyHX

コード例:

MY_STRUCT="""typedef struct __attribute__ ((__packed__)){
    uint8_t u8;
    uint16_t u16;
    uint32_t u32;
    uint64_t u64;
    int8_t i8;
    int16_t i16;
    int32_t i32;
    int64_t i64;
    long long int lli;
    float flt;
    double dbl;
    char string[12];
    uint64_t array[5];
} debugInfo;"""

PACKED_STRUCT='\x01\x00\x01\x00\x00\x01\x00\x00\x00\x00\x00\x01\x00\x00\x00\xff\x00\xff\x00\x00\xff\xff\x00\x00\x00\x00\xff\xff\xff\xff*\x00\x00\x00\x00\x00\x00\x00ff\x06@\x14\xaeG\xe1z\x14\x08@testString\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00'

if __name__ == '__main__':
    print "String:"
    print depack_bytearray_to_str(PACKED_STRUCT,MY_STRUCT,"<" )
    print "Bytes in Stuct:"+str(structSize(MY_STRUCT))
    nt=depack_bytearray_to_namedtuple(PACKED_STRUCT,MY_STRUCT,"<" )
    print "Named tuple nt:"
    print nt
    print "nt.string="+nt.string

結果は次のようになります。

String:
u8:1
u16:256
u32:65536
u64:4294967296
i8:-1
i16:-256
i32:-65536
i64:-4294967296
lli:42
flt:2.09999990463
dbl:3.01
string:u'testString\x00\x00'
array:(1, 2, 3, 4, 5)

Bytes in Stuct:102
Named tuple nt:
CStruct(u8=1, u16=256, u32=65536, u64=4294967296L, i8=-1, i16=-256, i32=-65536, i64=-4294967296L, lli=42, flt=2.0999999046325684, dbl=3.01, string="u'testString\\x00\\x00'", array=(1, 2, 3, 4, 5))
nt.string=u'testString\x00\x00'
于 2015-09-23T09:51:35.417 に答える