2013-05-12 2 views
2

저는 파이썬을 사용하여 바이너리 파일을 읽는 과정에서 혼란을 겪고 있습니다. 나는 둘 다 처음이에요. 그러니 나와 함께 견뎌주세요.파이썬을 사용하여 바이트 배열을 이진 파일로부터 언팩하는 방법은 무엇입니까?

파일 형식의 문서는 처음 16 바이트는 GUID 것을 알려줍니다 및 추가 읽기이 GUID 따라서 포맷 것을 저에게 말한다 :

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

내가있어 지금까지 우리가 먼저 압축을 해제 할 수있는 구조체에 3 개의 엔트리가 있지만, # 4에서 난처한 상황에 처하게됩니다. 그것은 8 바이트 배열입니다.하지만 그것을 풀어 낼 방법이 확실하지 않습니다. 내가 DATA4 잘못 뭐하는 거지

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 

? (저는 파이썬 3.2 BTW를 사용하고 있습니다)

데이터 1부터 3까지는 OK입니다. 만약 내가 hex()을 사용한다면 정확한 데이터를 얻고있다. (woohoo) 나는이 바이트 배열의 구문에 대해 실패하고있다.

편집 : MS-DTYP에 정의 된이 그것을 못을 박았다 나는이 GUID를 읽고 있어요

답변 :

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

당신은 bytearray와 함께 struct를 사용하고 있습니다. 이것들은 별개의 것입니다. 나는 bytearray에 익숙하지 않지만'struct.unpack()'은'bytearray'에 의해 반환 된 객체를 취하지 않을 것이라고 확신한다. – monkut

+1

@monkut : [버퍼 프로토콜] (http : //docs.python.org/3.3/c-api/buffer.html). – icktoofay

+0

@icktoofay 감사합니다! 알아 둘만한! – monkut

답변

6

을, 당신은 거기에 수 8을 넣어해야합니다

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

the docs에서 :

포맷 문자 적분 반복 횟수가 선행 될 수 있습니다. 예를 들어, 형식 문자열 '4h'는 'hhhh'와 정확히 동일 함을 의미합니다.

... 's'형식 문자

는 수는 바이트의 길이 아닌 다른 형식의 문자와 같은 반복 횟수로 해석됩니다; 예를 들어, '10'은 10 바이트 문자열을 의미하고 '10c'는 10 문자를 의미합니다. 카운트가 주어지지 않은 경우, 디폴트는 1입니다. 패킹의 경우, 캐릭터 라인은 잘라 버려 지거나 적합하게하기 위해서 null 바이트로 패딩됩니다. 압축을 풀 때 결과 바이트 객체는 항상 정확히 지정된 바이트 수를가집니다. 특별한 경우로 '0'은 빈 문자열 하나를 의미합니다 ('0c'는 0 문자를 의미 함).


그러나, 나는 당신이 처음에이 일을하는 이유를 모르겠어요.

fp.read(8)은 8 바이트의 bytes 개체를 제공합니다. 8 바이트의 bytes 개체가 필요합니다. 그래서, 그냥 이렇게 :

Data4 = fp.read(8) 

변경 가능한 복사본을 만드는 것 외에는 아무런 효과가없는 bytesbytearray A를 변환.포장을 풀면 시작한 것과 동일한 bytes의 사본을 돌려줍니다. 왜?


음, 사실, struct.unpack 그 하나 개의 값이 tuple 당신이 시작 같은 bytes의 복사본입니다 반환,하지만 당신은 할 수

그와 : 당신이 왜의 문제를 제기

Data4 = (fp.read(8),) 

처음에는 네 개의 단일 요소 튜플이 필요합니다. 정당한 이유없이 온통 Data1[0] 등을 할 것입니다. 왜 안돼? 이이 UUID를 읽어 의미 경우 물론


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

, 그것은 니켈과 카드뮴 광석에서 자신의 배터리를 구축하려고하는 것보다 "포함 배터리"를 사용하는 것이 좋습니다. icktoofay가 말했듯이, 단지 uuid 모듈 사용 :

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

을하지만 파이썬의 uuid가 4-2-2-1-1-6 형식이 아닌 4-2-2-8 형식을 사용하는 점에 유의하십시오. 이 형식이 정말로 필요한 경우에는 변환해야합니다. 즉, struct 또는 조금 어색한 쪽을 의미합니다. (Microsoft의 GUID는 4-2-2-2-6 형식을 사용하여 더욱 재미있게 만듭니다.이 형식은 네이티브 엔디안에서 처음 3자를, 빅 엔디안에서 마지막 두자를 나타내는 표현식과 같지 않습니다. 일을 더 쉽게하기 위해서 ...)

+0

또한 'bytearray'는 필요하지 않습니다 (다 치지는 않겠지 만). – icktoofay

+0

@icktoofay : 당신 말이 맞아요.하지만 전체 포장을 풀지 않아도됩니다. – abarnert

+0

그건 내가 생각조차하지 못했던 아주 좋은 지적입니다. – icktoofay

3

UUIDsthe uuid module 파이썬을 지원합니다. 이 같은 수행은 8 바이트 문자열을 원하는 경우에

import uuid 

my_uuid = uuid.UUID(bytes_le=fp.read(16)) 
+1

'bytes'는 빅 엔디안 순서입니다. OP의 데이터 (그가'struct' 형식을 가지고 있다고 가정)는 리틀 엔디안 형식입니다. 그래서, 여기에'bytes_le'이 필요합니다.'bytes'가 아닙니다. – abarnert

+1

또한 파이썬의 UUID가 4-2-2-1-8이 아니라 4-2-2-1-1-6이라는 사실에 주목할 필요가 있습니다. 따라서 4-2-2-8 형식을 얻으려면 수동으로'fields'를 변환해야합니다. – abarnert

관련 문제