3

私は、Python を使用してバイナリ ファイルを読み取るための短期集中コースを自分自身に与えています。どちらも初心者ですので、ご容赦ください。

ファイル形式のドキュメントによると、最初の 16 バイトは GUID であり、さらに読むと、この GUID は次のようにフォーマットされていることがわかります。

typedef struct {
  unsigned long Data1;
  unsigned short Data2;
  unsigned short Data3;
  byte Data4[8];
} GUID, 
 UUID, 
 *PGUID;

構造体の最初の 3 つのエントリをアンパックできるようになりましたが、#4 で困惑しています。8バイトの配列だと思いますが、解凍する方法がわかりません。

import struct

fp = open("./file.bin", mode='rb')

Data1 = struct.unpack('<L', fp.read(4)) # unsigned long, little-endian
Data2 = struct.unpack('<H', fp.read(2)) # unsigned short, little-endian 
Data3 = struct.unpack('<H', fp.read(2)) # unsigned short, little-endian
Data4 = struct.unpack('<s', bytearray(fp.read(8))) # byte array with 8 entries?

struct.error: unpack requires a bytes object of length 1

Data4 の何が間違っていますか? (私はPython 3.2 BTWを使用しています)

Data1 から 3 までは OK です。それらに hex() を使用すると、期待どおりの正しいデータが得られます (woohoo)。このバイト配列の構文でフェールオーバーしているだけです。

編集:答え

MS-DTYPで定義されているGUIDを読んでいますが、これでうまくいきました:

data = uuid.UUID(bytes_le=fp.read(16))
4

2 に答える 2

11

88 バイトの文字列が必要な場合は、そこに数字を入れる必要があります。

struct.unpack('<8s', bytearray(fp.read(8)))

ドキュメントから:

フォーマット文字の前に、整数の繰り返し回数を指定できます。たとえば、フォーマット文字列 '4h' は 'hhhh' とまったく同じ意味です。

's' フォーマット文字の場合、カウントはバイトの長さとして解釈され、他のフォーマット文字のような繰り返しカウントではありません。たとえば、'10s' は単一の 10 バイト文字列を意味し、'10c' は 10 文字を意味します。カウントが指定されていない場合は、デフォルトで 1 になります。パッキングでは、文字列が収まるように、必要に応じて切り捨てられるか、null バイトが埋め込まれます。アンパックの場合、結果のバイト オブジェクトには常に、指定された正確なバイト数が含まれます。特殊なケースとして、'0s' は単一の空の文字列を意味します ('0c' は 0 文字を意味します)。


ただし、そもそもなぜこれを行っているのかわかりません。

fp.read(8)8バイトのbytesオブジェクトを提供します。8 バイトのbytesオブジェクトが必要です。だから、これをしてください:

Data4 = fp.read(8)

bytesを aに変換しbytearrayても、変更可能なコピーを作成する以外には何の効果もありません。解凍すると、最初に使用したのと同じコピーが返さbytesれます。なぜ?


実際には、1 つの値が最初に作成したものと同じコピーである をstruct.unpack返しますが、次の方法でそれを行うことができます。tuplebytes

Data4 = (fp.read(8),)

そもそもなぜ 4 つの単一要素タプルが必要なのかという疑問が生じます。Data1[0]正当な理由もなく、いたるところで などを行うことになります。なぜこれではないのですか?

Data1, Data2, Data3, Data4 = struct.unpack('<LHH8s', fp.read(16))

もちろん、これが UUID を読み取ることを意図している場合は、ニッケルとカドミウム鉱石から独自のバッテリーを構築しようとするよりも、「付属のバッテリー」を使用する方が常に優れています。icktoofay が言うように、uuidモジュールを使用するだけです:

data = uuid.UUID(bytes_le=fp.read(16))

ただし、Pythonuuidは 4-2-2-8 形式ではなく、4-2-2-1-1-6 形式を使用することに注意してください。本当にその形式が必要な場合は、変換する必要があります。つまり、structとにかく少しいじる必要があります。(Microsoft の GUID は、どちらとも同じではない 4-2-2-2-6 形式を使用し、最初の 3 つをネイティブ エンディアンで、最後の 2 つをビッグ エンディアンで表すことで、物事をさらに楽しくします。物事を簡単にするのが好きです…)

于 2013-05-12T21:42:20.837 に答える