struct
모듈은 binary data를 보다 쉽게 파싱해주는 기능을 제공한다.
C
언어의 구조체로 명시된 binary data를 네트워크 등으로 받은 경우나,
binary format으로 특정 header정보를 가지고 있는 파일들을 읽어들일 때,
특정 바이트 크기에 할당된 변수 값들을 Python의 변수들에 제대로 할당하는데 많이 사용된다.
크게 다음 3가지의 함수를 이용한다.
pack
C
언어의 구조체 등으로 읽어들일 수 있는 binary data에 해당하는 bytes
객체를 만들어내는 함수.
현재 python의 변수들의 값들을 지정된 format의 binary data에 해당하는 bytes
객체로 변경한다.
bytes_v = struct.pack(format, variable0, variable1, ...)
- Python 변수들 (`variable0, variable1, ...)을
- 특정
format
에 따라 인코딩(?)하여 bytes
객체를 생성함.
해당 bytes
객체를 파일로 저장하면 C
언어로 같은 format
을 따르는 구조체 변수로 읽어들일 수 있음.
위에서 format
을 지정하는 format string
은 다음의 표를 참고할 것.
Formatting String | Python | C | Size (Bytes) |
|
x | - | padding type | 1 | Null byte 로 패딩 |
C | str (len이 1인) | char | 1 | unsigned byte |
b | signed byte (bytes or int) | signed char | 1 | signed byte |
B | unsigned byte (byte or int) | unsigned char | 1 | unsigned byte |
h | int | short | 2 | 정수형 |
H | int | unsigned short | 2 | 정수형 |
i | int | int | 4 | 정수형 |
I (uppercase of i) | int | unsigned int | 4 | 정수형 |
l (lowercase of L) | int | long | 4 | 정수형 |
L | int | unsigned long | 4 | 정수형 |
q | int | long long | 8 | 정수형 |
Q | int | unsigned long long | 8 | 정수형 |
f | float | float | 4 | single precision floating point number |
d | float | double | 8 | double precision floating point number |
s | str (or bytes) | char[] | count | null terminated string |
p | str (or bytes) | char[] | 1+count | Pascal string |
단 bytes
로 pack 할 경우에는 endianess도 지정해줘야 함.
format string
의 가장 앞에 다음의 문자들로 지정한다.
Formatting Character (Endianess Character) |
Byte Order | Size | Alignment |
@ | Native | Native (C의 sizeof에 의해 결정) | Native |
= | Native | Standard (앞서 테이블에 기재된 size) | none |
> | big endian | Standard | none |
< | littel endian | Standard | none |
! | network (=big endian) | Standard | none |
unpack
pack
의 inverse에 해당한다.
보통 다른 software와 패킷 통신 등을 할 때 많이 이용됨.
binary data 에 해당하는 bytes
객체 data_bytes
을 parsing하여 값들을 가진 tuple
을 생성한다고 생각하면 쉽다.
tuple_v = struct.unpack(format, data_bytes)
calcsize
앞서 애기한 format_string
을 argument로 받아서 해당 format_string
의 바이트 크기를 반환해줌.
int_v = struct.calcsize(format_string)
Example 1
임의의 png파일을 다운로드하고 이름을 test.png
로 바꾼 후
다음 python code의 py파일과 같은 디렉토리 놓고 수행해 볼 것.
- png가 올바른 파일인지 확인하고,
- header로부터 width와 height를 얻어내는 프로그램임.
fstr = 'test.png'
valid_png_hdr = b'\x89PNG\r\n\x1a\n'
with open(fstr,'rb') as f:
read_data = f.read(30)
print(read_data[:8])
#w,h = struct.unpack('>16x2L6x', read_data)
if read_data[:8] == valid_png_hdr:
w, h = struct.unpack(
'>LL', # '2L',
read_data[16:24]
)
print( f"{fstr} is a valid png file. \n {w=},{h=}")
else:
print(f'{fstr} is not a valid png file')
Example 2
다음은 little endian 을 사용하여 다음의 C
구조체에 해당하는 데이터를 받아서 처리하는 경우의 예임.
(socket으로부터 받은 data를 pack
을 통해 가상으로 만들어서 처리함)
import struct
i = 2
a = 1.
b = 3.
c = 88.
data_bytes = struct.pack('<Hfff',i,a,b,c)
print(data_bytes)
parsed = struct.unpack('<Hfff',data_bytes)
print(parsed)
pack
에 대응하는 구조체 (C 언어)는 다음과 같음.
typedef union
{
uint8_t data[14]:
struct __attribute__((packed))
{
uint16_t i;
float a;
float b;
float c;
};
} dspacket_s;
참고자료들
https://docs.python.org/ko/3/library/struct.html
https://dsaint31.me/mkdocs_site/CE/ch04/ce04_02_byte_ordering/
https://coding-yoon.tistory.com/120
https://coding-yoon.tistory.com/171
'Python' 카테고리의 다른 글
[Python] Unicode and Python : Unicode Literal (0) | 2024.01.16 |
---|---|
[Python] Binary Operations (0) | 2024.01.15 |
[Python] bytes and bytearray: Binary Data for Python (0) | 2024.01.15 |
[python] Text mode vs. Binary mode: File open (0) | 2024.01.15 |
[pandas] 데이터 타입에 따른 column 추출 (0) | 2024.01.12 |