Computer >> 컴퓨터 >  >> 프로그래밍 >> Python

파이썬 바이너리 데이터 처리: struct 모듈 활용법 총정리

파이썬 표준 라이브러리의 struct 모듈은 C 언어의 구조체(struct)와 파이썬의 bytes 객체 간 변환을 수행할 때 매우 유용하게 사용됩니다. 이러한 변환 작업은 모듈 레벨 함수를 통해서도 가능하고, struct 모듈에 정의된 Struct 클래스와 그 메서드를 통해서도 수행할 수 있습니다.

변환 함수들은 포맷 문자열(format string)을 사용하며, 이 문자열에서 바이트 순서(byte order), 크기(size), 정렬(alignment) 방식은 아래 표의 포매팅 문자에 따라 결정됩니다.

문자바이트 순서크기정렬
@네이티브(native)네이티브(native)네이티브(native)
=네이티브(native)표준(standard)없음
<리틀 엔디안(little-endian)표준(standard)없음
>빅 엔디안(big-endian)표준(standard)없음
!네트워크(= 빅 엔디안)표준(standard)없음

C 타입과 파이썬 타입의 대응 관계

다음 표는 C 언어 타입 변수를 나타내는 포맷 문자와 그에 대응하는 파이썬 타입을 보여줍니다.

포맷C 타입파이썬 타입
x패딩 바이트(pad byte)값 없음
cchar길이 1인 bytes
b / Bsigned char / unsigned char정수(integer)
?_Boolbool
h / Hshort / unsigned short정수(integer)
i / Iint / unsigned int정수(integer)
l / Llong / unsigned long정수(integer)
ffloat실수(float)
ddouble실수(float)
schar[]bytes
pchar[] (Pascal 문자열)bytes
Pvoid *정수(integer)

struct 모듈의 주요 함수

struct 모듈에는 다음과 같은 핵심 함수들이 정의되어 있습니다.

pack()

이 함수는 지정한 포맷 문자열에 따라 값들을 패킹(packing)하여 bytes 객체로 반환합니다. 포맷 문자열의 형식 문자는 전달되는 값들과 반드시 일치해야 합니다.

unpack()

이 함수는 버퍼(buffer)에서 포맷 문자열에 따라 값을 언패킹(unpacking)합니다. 결과가 단 하나의 항목만 포함하더라도 항상 튜플(tuple) 형태로 반환됩니다.

다음 코드는 이 두 함수의 사용 예를 보여줍니다.

import struct
student=(1, b'Rahul', 65.75)
packed=struct.pack('I 5s f', *student)
print ('packed data:',packed)

unpacked=struct.unpack('I 5s f', packed)
print ('unpacked data:',unpacked)

실행 결과

packed data: b'\x01\x00\x00\x00Rahul\x00\x00\x00\x00\x80\x83B'
unpacked data: (1, b'Rahul', 65.75)

Struct 클래스 활용하기

패킹/언패킹 작업은 Struct 클래스의 메서드를 통해서도 수행할 수 있습니다. Struct 객체를 한 번 생성한 후 그 메서드를 호출하는 방식은, 동일한 포맷 문자열로 struct 모듈의 함수를 반복 호출하는 것보다 더 효율적입니다. 그 이유는 포맷 문자열이 한 번만 컴파일되기 때문입니다.

Struct(format)

이 생성자는 지정한 포맷 문자열 형식에 따라 바이너리 데이터를 읽고 쓰는 새로운 Struct 객체를 반환합니다.

pack()

컴파일된 포맷을 사용한다는 점을 제외하면 pack() 함수와 동일하게 동작하는 메서드입니다.

unpack()

컴파일된 포맷을 사용한다는 점을 제외하면 unpack() 함수와 동일하게 동작하는 메서드입니다.

다음 예제는 Struct 클래스를 사용해 파이썬 데이터를 패킹하고 언패킹하는 방법을 보여줍니다.

s = struct.Struct('I 5s f')
packed=s.pack(*student)
print (packed)
unpacked = s.unpack(packed)
print (unpacked)

namedtuple로 결과 변환하기

패킹된 데이터는 namedtuple 객체로 직접 변환하여 파싱할 수도 있습니다. 이렇게 하면 인덱스 대신 의미 있는 필드 이름으로 데이터에 접근할 수 있어 가독성이 크게 향상됩니다.

from collections import namedtuple
newstudent = namedtuple('newstudent','No Name Marks')
s1 = newstudent._make(struct.unpack('I 5s f', packed))
print (s1)

실행 결과

newstudent(No=1, Name=b'Rahul', Marks=65.75)