Tipps zum Umgang mit Binärdateien in Python

Hier sind einige Tipps zum Arbeiten mit Binärdateien in Python.

Es gibt zwei Möglichkeiten, mit Binärdateien in Python zu arbeiten: das Modul struct und die Klasse ctypes.Structure. Grundsätzlich verwendet das Modul struct die Klasse ctypes.Structure, wenn Sie einige Bytes Binär verarbeiten möchten oder wenn Sie mit mehr Bytes oder C / C ++ arbeiten möchten.

struct Modul

Lesen wir als Beispiel die Binärdatei einer PNG-Datei. In einer PNG-Datei sind die ersten 8 Bytes im Header festgelegt. Die 9. bis 18. Datenbytes werden im IHDR-Bereich (um genau zu sein Teil des IHDR), in der vertikalen und horizontalen Größe des Bildes, in der Bittiefe und im Farbmodus gespeichert.

import struct

png_data = open("sample.png ", "rb").read()

struct.unpack_from(">I4sIIBB", png_data, 8)
# (13, b'IHDR', 250, 156, 8, 2)

Sie können die Daten mit struct.unpack lesen, aber Sie erhalten eine Fehlermeldung, wenn der Offset und die Größe des von Ihnen angegebenen Puffers nicht genau gleich sind. Struct.unpack_from ist nützlich, wenn Sie einen Teil der Daten lesen möchten.

Putten ist "x"

Beim Lesen der Binärdatei kommt das Putten (Staubbereich zum Ausrichten) auf jeden Fall heraus. Das "x" -Format ist praktisch, da es die Daten überspringt.

data = b'd\x00\xb0\x04'

# NG
kind, _, value = struct.unpack("BBH", data)

# Yes!
kind, value = struct.unpack("BxH", data)

struct.Struct-Klasse

Die Klasse struct.Struct ist eine Klassifizierung der Formatzeichenfolge des Moduls struct. Da das Format analysiert wird, wenn die Klasse instanziiert wird, ist es schneller, die Instanz im Voraus zu erstellen, wenn in der Schleife wiederholt "packen" / "entpacken". Es ist verwirrend mit der Klasse ctypes.Structre.

point = struct.Struct("HH")

for x, y in zip(range(10), range(10)):
    point.pack(x, y)

Liste der Formatzeichen

Brief C Sprachtyp Standardgröße
x Biss setzen 1
c char 1
b signed char 1
B unsigned char, BYTE 1
? _Bool 1
h short 2
H unsinged short, WORD 2
i int 4
I unsigned int, DWORD 4
l long, LONG 4
L unsigned long, ULONG 4
q long long, LONGLONG 8
Q unsigned long long, ULONGLONG 8
n ssize_t(Python3.3 oder später) Nur einheimisch
N size_t(Python3.3 oder später) Nur einheimisch
f float 4
d double 8
s char[] -
p char[] -
P void * -

Beispiel für Formatzeichen:

BITMAPINFOHEADER-Struktur


typedef struct tagBITMAPINFOHEADER {
    DWORD  biSize;
    LONG   biWidth;
    LONG   biHeight;
    WORD   biPlanes;
    WORD   biBitCount;
    DWORD  biCompression;
    DWORD  biSizeImage;
    LONG   biXPelsPerMeter;
    LONG   biYPelsPerMeter;
    DWORD  biClrUsed;
    DWORD  biClrImportant;
} BITMAPINFOHEADER;

Zeichen im BITMAPINFOHEADER-Strukturformat


"IllHHIIllII"

Liste der Bytereihenfolge und Ausrichtung

Brief Bytereihenfolge Größe Ausrichtung
@ Native Native Native
= Native Standardgröße Keiner
< Kleiner Inder Standardgröße Keiner
> Big Endian Standardgröße Keiner
! Big Endian Standardgröße Keiner

@Wann=Der Unterschied von(CPU=amd64,OS=Ubuntu64bit)


struct.calcsize("BI")
# 8

struct.calcsize("=BI")
# 5

Beachten Sie, dass die Ausrichtung "keine" lautet, wenn Sie den Endian explizit angeben.

ctypes.Structure-Klasse

Sie können mit C / C ++ - Strukturen in der Klasse ctypes.Structure arbeiten. Wenn Sie versuchen, viele Daten mit dem Modul 'Struktur' zu lesen, ähnelt das Format einem Zauberspruch. Wenn Sie also viele Binärdaten fest lesen möchten, sollten Sie die Klasse ctypes.Structure verwenden. Machen wir das.

Strukturgrundlagen

Erben Sie ctypes.Structure und definieren Sie die Typen in _field_.

from ctypes import *

"""
typedef struct {
    char identity[4];
    uint16_t x;
    uint16_t y;
} TestStructure;
"""
class TestStructure(Structure):
    _fields_ = (
        ('identity', c_char * 4),
        ('x', c_uint16),
        ('y', c_uint16),
    )

Die Instanz ist wie folgt definiert.

t = TestStructure(b"TEST", 100, 100)