2012-02-11 9 views
1

최근 바이너리 데이터를 파이썬으로 구문 분석하는 활동을 시작했지만 "바이트"항목이 파이썬으로 처리되는 방식에 혼란 스럽습니다. 예 : 다음 통역자 대화 :파이썬의 바이트에 대해 혼동을 느낀다

>>> f = open('somefile.gz', 'rb') 
>>> f 
<open file 'textfile.gz', mode 'rb' at 0xb77f4d88> 
>>> bytes = f.read() 
>>> bytes[0] 
'\x1f' 
>>> len(bytes[0]) 
1 
>>> int(bytes[0]) <---- calling __str__ automatically on bytes[0] ? 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
ValueError: invalid literal for int() with base 10: '\x1f' 

상기 세션 [0]은 1 바이트의 크기를 갖지만 바이트 __str__ 진수 표현은 하나라는 것을 나타낸다. 걱정할 필요는 없지만 바이트 [0]을 단일 바이트로 처리하려고하면 펑키 한 동작이 발생합니다.

사양에 16 진수, 2 진수 및 10 진수 표현이 포함 된 일부 사양을 기반으로 이진 스트림을 구문 분석하거나 해석하려면 어떻게해야합니까?

예 : "처음 두 바이트는 \xbeef, 그 다음은 십진수 8이고 그 뒤에 8 비트의 각 비트가 플래그를 나타내는 팩형 비트 필드가 오는가?이 작업을 쉽게 수행 할 수있는 몇 가지 모듈이 있지만 '처음부터 그렇게 할 거라고.

을 내가하지만 struct 모듈에 대한 참조를 보았다 바이트가 새 모듈을 도입하지 않고 직접 읽을 확인하는 방법은 같은? 뭔가가없는 bytes[0] == 0xbeef

누군가가 나를 도와 주시겠습니까? 파이썬을 사용하여 스펙을 따르는 바이너리 데이터를 어떻게 파싱 하는가? 감사.

+1

"새 모듈 소개"에 대해 걱정하지 마십시오. Python 표준 라이브러리의 많은 모듈에는 핵심 기능이 포함되어 있습니다. 핵심 기능은 단순히 자체의 네임 스페이스로 분리되지만 언어의 필수 부분입니다. 대부분의 모듈은 인터프리터로 컴파일됩니다 (적어도 CPython을 사용할 때). –

답변

5

당신은 Python 2.x를 사용하고 있습니다. Python 3.0 이전 버전에서는 이진 파일조차도 문자열을 반환합니다. "bytes"객체를 실제로 호출하는 것은 문자열입니다. "bytes [0]"과 같이 문자열을 인덱싱하면 1 문자 문자열 만 반환됩니다.

구조체 모듈은 아마 당신이 원하는에 가장 적합한 것,하지만 당신이 정말로 원하는 경우에 당신은 당신이 그것없이 물어 무엇을 할 수 : "바이트처럼 뭔가 [0] == 0xbeef"

0xbeef는 2 바이트 시퀀스이지만 바이트 [0]은 단일 바이트이기 때문에 작동하지 않습니다. 다음과 같이 대신 할 수 있습니다 :

bytes[0:2] == b'\xbe\xef' 

예상치 못한 일들이 조금 있습니다. 이진 파일을 읽으면 문자열이 아닌 1 바이트 부호없는 정수로 작동하는 bytes 개체가 반환됩니다.

+0

잠깐, 나는 바이트가 파이썬 3.x 일 뿐이라고 생각했다. 16 진수 값 앞의 그'b' 지정자는 무엇인가? – sasuke

+0

@asasuke : 파이썬 2.7 콘솔을 열어서 거기에 넣으려고한다면 거기에서도 작동한다는 것을 알게 될 것입니다. 따라서, 그것은 위와 같은 방법으로 쓰기가 가능합니다 (Good Thing). –

+0

@SvenMarnach 여기에 바이트가 변경 가능하다고 주장하는 사람은 아무도 없습니다. 아마도'=='와'='를 혼동하는 것일까? 우리는 시퀀스의 처음 두 바이트가 시퀀스를 변경하지 않고 어떤 값과 같은지 여부를 테스트하는 방법에 대해 설명합니다. – Weeble

2

구문 분석하고 싶다면 이진 데이터는 struct 모듈을 확인하십시오.

: 당신이 부호없는 short로서 처음 2 바이트를 읽고, 0xbeef으로 테스트를 수행하려는 경우

>>> from struct import * 
>>> pack('hhl', 1, 2, 3) 
'\x00\x01\x00\x02\x00\x00\x00\x03' 
>>> unpack('hhl', '\x00\x01\x00\x02\x00\x00\x00\x03') 
(1, 2, 3) 
>>> calcsize('hhl') 
8 

그래서 더 약 unpack :

알아보기 : 여기에 문서의 예입니다

struct.unpack('H', bytes[0:2]) == 0xbeef 
+0

흠 ...하지만 어디서나 'ord'를 사용하지 않았습니까? 어쩌면 나는 명확하지 않았다 : 내가'bytes [0] == 0xbeef' 또는 더 구체적으로 할 수있는 방법이 있는가, 왜 그것이 허용되지 않는가? – sasuke

+0

@asasuke : 파이썬의 문자열은 변경할 수 없으므로 변경할 수 없습니다.(또한, 가능하다해도 처음에는 16 비트 숫자를 할당 할 수 없다.) 데이터를 만드는 동안 목록을 사용하고 마지막으로 그것을'pack()'하는 것이 좋다. 이진 문자열로. –

+0

글쎄, bytes [0]은 1 바이트 길이이고, 0xbeef는 2 바이트 길이입니다. 또한 bytes [0]은 문자열이고 0xbeef는 int입니다. struct가 없다면,''map (ord, a) == [0xbe, 0xef]''와 같은 것을 할 필요가 있습니다. 그러나 little/big 엔디안은 신경 쓰지 않습니다. – tito

관련 문제