HOWTO · Python
Bytes in eine Datei schreiben in Python
Dieses Tutorial demonstriert, wie man in Python Bytes in eine Binärdatei schreibt
Auf dieser Seite
Um Bytes in eine Datei zu schreiben, rufe open() mit dem Modus wb auf und übergib der write()-Methode der Datei ein bytes-artiges Objekt. Verwende einen with-Block, damit die Datei automatisch geschlossen wird. Wenn du vorhandene Inhalte ergänzen möchtest, wähle stattdessen ab.
Jedes Codebeispiel legt seine Dateien in einem temporären Verzeichnis an. Python entfernt dieses Verzeichnis, sobald der with-Block des Beispiels endet. Wenn du eine Datei behalten möchtest, ersetze ihren temporären Pfad durch den gewünschten Zielpfad.
Bytes in Python in eine Datei schreiben
Das w in wb öffnet eine Datei zum Schreiben: Falls nötig, wird sie erstellt; eine vorhandene Datei wird bereits beim Öffnen geleert. Das b aktiviert den Binärmodus. Python schreibt die Bytes dann ohne Textkodierung oder Übersetzung von Zeilenumbrüchen.
Führe dieses Beispiel aus, um Daten zu schreiben und wieder einzulesen:
Der Code und die angezeigten Bezeichnungen oder Ausgaben in diesem Abschnitt bleiben auf Englisch.
from pathlib import Path
from tempfile import TemporaryDirectory
with TemporaryDirectory() as directory:
path = Path(directory) / "example.bin"
data = b"This is some binary data."
with open(path, "wb") as file:
written = file.write(data)
with open(path, "rb") as file:
saved = file.read()
print(written)
print(saved == data)
25
True
Bei dieser normalen gepufferten Datei gibt write() die Anzahl der geschriebenen Bytes zurück. Das Programm gibt diese Anzahl aus und vergleicht die gespeicherten Daten mit dem Original. Das Einlesen erfolgt, nachdem der Schreibblock die Datei geschlossen und den Python-Puffer geleert hat. Die Endung .bin ist eine Namenskonvention; der Binärmodus wird durch das Modusargument festgelegt.
Verwende xb, wenn du eine Datei nur erstellen möchtest, falls sie noch nicht existiert. Anders als wb überschreibt dieser Modus keine vorhandene Zieldatei. Keiner der beiden Modi erstellt fehlende übergeordnete Verzeichnisse.
Mehrere Bytefolgen in eine Datei schreiben
Lass die Datei geöffnet, während du nacheinander einzelne Datenblöcke schreibst. Jeder Aufruf von write() setzt an der aktuellen Position fort. Würdest du die Datei innerhalb der Schleife mit wb öffnen, gingen die zuvor geschriebenen Blöcke verloren.
Der Code und die angezeigten Bezeichnungen oder Ausgaben in diesem Abschnitt bleiben auf Englisch.
from pathlib import Path
from tempfile import TemporaryDirectory
chunks = [b"First line.\n", b"Second line.\n", b"Third line.\n"]
with TemporaryDirectory() as directory:
path = Path(directory) / "chunks.bin"
with open(path, "wb") as file:
for chunk in chunks:
file.write(chunk)
Jeder Block muss bytes-artige Daten enthalten, zum Beispiel bytes, bytearray oder eine geeignete Puffersicht. Du kannst auch ein Iterable mit Bytefolgen an file.writelines(chunks) übergeben. Trotz seines Namens fügt writelines() weder Trennzeichen noch Zeilenumbrüche hinzu. Falls du diese benötigst, nimm sie in die Datenblöcke auf. Mit einer Schleife kannst du außerdem eintreffende Blöcke verarbeiten, ohne die gesamte Nutzlast zuvor im Speicher zusammenzufügen.
Ein bytearray in eine Datei schreiben
Ein bytes-Objekt ist unveränderlich, während du mit einem bytearray einzelne Bytes ändern oder die Folge vor dem Speichern erweitern kannst. Beide Typen lassen sich direkt in eine Binärdatei schreiben.
Der Code und die angezeigten Bezeichnungen oder Ausgaben in diesem Abschnitt bleiben auf Englisch.
from pathlib import Path
from tempfile import TemporaryDirectory
payload = bytearray(b"Line 1\n")
payload.extend(b"Line 2\n")
payload[0] = ord("l")
with TemporaryDirectory() as directory:
path = Path(directory) / "bytearray.bin"
with open(path, "wb") as file:
file.write(payload)
Hier fügt extend() eine weitere Folge hinzu, und die Zuweisung über den Index ändert das erste Byte. Für den Schreibvorgang brauchst du keine Umwandlung mit bytes(payload). Verwende diese Umwandlung, wenn du an anderer Stelle einen unveränderlichen Wert benötigst. Spätere Änderungen am bytearray aktualisieren die Datei nicht automatisch.
BytesIO-Daten in eine Datei schreiben
BytesIO aus dem Modul io stellt einen binären Datenstrom im Arbeitsspeicher bereit. Die Methode getbuffer() gibt eine Sicht auf den gesamten zugrunde liegenden Puffer zurück, ohne dessen Inhalt in ein separates bytes-Objekt zu kopieren.
Der Code und die angezeigten Bezeichnungen oder Ausgaben in diesem Abschnitt bleiben auf Englisch.
from io import BytesIO
from pathlib import Path
from tempfile import TemporaryDirectory
with TemporaryDirectory() as directory:
path = Path(directory) / "buffer.bin"
with BytesIO() as buffer:
buffer.write(b"Header\n")
buffer.write(b"Payload\n")
with buffer.getbuffer() as view:
with open(path, "wb") as file:
file.write(view)
Die Sicht umfasst alle gepufferten Daten, unabhängig von der aktuellen Position des Datenstroms. Solange die Sicht besteht, kann das Objekt BytesIO weder vergrößert noch geschlossen werden. Die verschachtelten Kontextmanager geben die Sicht frei, bevor sie den Datenstrom schließen. Verwende buffer.getvalue(), wenn du stattdessen einen bytes-Wert benötigst. Wenn du mit buffer.read() eine Kopie erstellen und am Anfang beginnen möchtest, rufe zuerst buffer.seek(0) auf.
Bytes anhängen oder an einer bestimmten Position schreiben
Öffne die Datei mit ab, um Bytes am Ende anzufügen, ohne vorhandene Inhalte zu löschen. Dieser Modus erstellt das Ziel auch, falls es noch nicht existiert. Um Bytes an einem bestimmten Offset einer vorhandenen Datei zu überschreiben, verwende r+b und die Methode seek() des Dateiobjekts.
Der Code und die angezeigten Bezeichnungen oder Ausgaben in diesem Abschnitt bleiben auf Englisch.
from pathlib import Path
from tempfile import TemporaryDirectory
with TemporaryDirectory() as directory:
path = Path(directory) / "records.bin"
with open(path, "wb") as file:
file.write(b"ABCDEF")
with open(path, "ab") as file:
file.write(b"GH")
with open(path, "r+b") as file:
file.seek(2)
file.write(b"xy")
seek(2) setzt die Position auf Byte-Offset 2, gemessen vom Dateianfang. Der nächste Schreibvorgang ersetzt zwei Bytes, ohne Daten einzufügen oder den verbleibenden Rest zu entfernen. Wenn du nach einem kürzeren Ersatz nachfolgende Bytes löschen möchtest, rufe ausdrücklich truncate() auf.
r+b setzt eine vorhandene Datei voraus und lässt deren Inhalte beim Öffnen bestehen. w+b erlaubt Lesen und Schreiben, leert die Datei jedoch zuerst. Verwende den Anhängemodus nicht für Änderungen an einer bestimmten Position: Schreibvorgänge werden ans Ende geleitet, und es ist nicht portabel, dieses Verhalten durch Positionieren zu umgehen. Allein durch das Positionieren hinter dem Dateiende wird die Datei nicht verlängert. Ein anschließender Schreibvorgang kann sie verlängern; wie die Lücke gespeichert wird, hängt vom Dateisystem ab.
Pufferung und große Schreibvorgänge
Normale Binärdateien, die mit open() geöffnet werden, sind standardmäßig gepuffert. Eine ausdrückliche Einstellung wie buffering=8192 fordert eine Puffergröße an. Sie garantiert weder schnellere Schreibvorgänge noch, dass jeder Schreibvorgang des Betriebssystems genau 8192 Bytes umfasst.
Bei großen, erzeugten Datenmengen kannst du wiederverwendbare Blöcke schreiben, statt ein einziges großes Objekt zusammenzustellen:
Der Code und die angezeigten Bezeichnungen oder Ausgaben in diesem Abschnitt bleiben auf Englisch.
from pathlib import Path
from tempfile import TemporaryDirectory
chunk = b"record\n" * 1024
with TemporaryDirectory() as directory:
path = Path(directory) / "large.bin"
with open(path, "wb", buffering=8192) as file:
for _ in range(100):
file.write(chunk)
Dieses Beispiel zeigt eine optionale Puffereinstellung und verwendet denselben Datenblock wiederholt. Ermittle geeignete Puffergrößen durch Messungen mit deiner tatsächlichen Arbeitslast; eine allgemein beste Größe gibt es nicht. Beim Schließen der Datei wird der Python-Puffer geleert. Ein früherer Aufruf von flush() überträgt gepufferte Daten an den zugrunde liegenden Datenstrom, garantiert für sich allein aber nicht, dass sie dauerhaft auf einem Speichermedium gespeichert werden.
Häufige Fragen zum Schreiben von Bytes
Wie lese ich die Bytes wieder ein? Öffne die Datei mit rb und rufe file.read() auf. Der Rückgabewert ist bytes. Bei einer großen Datei solltest du Blöcke fester Größe lesen, statt alles auf einmal in den Speicher zu laden.
Kann ich im Binärmodus Text schreiben? Kodiere ihn zuerst, zum Beispiel mit text.encode("utf-8") oder bytes(text, "utf-8"). Zum Wiederherstellen des Textes muss beim Lesen dieselbe Kodierung verwendet werden. Wenn du ausschließlich Text speichern möchtest, ist das Öffnen im Textmodus mit encoding="utf-8" möglicherweise verständlicher.
Warum meldet write() einen TypeError? Ein binärer Datenstrom benötigt bytes-artige Daten. Ein str, eine Ganzzahl oder eine Liste erfüllt diese Anforderung nicht, wenn du sie direkt übergibst. Kodiere Text oder wandle eine Folge ganzzahliger Bytewerte mit bytes(values) um. Jede Ganzzahl muss zwischen 0 und 255 liegen.
Was passiert bei einer leeren Nutzlast? Das Schreiben von b"" fügt keine Bytes hinzu. Eine vorhandene Datei wurde beim Öffnen mit wb jedoch bereits geleert. Verwende ab, um vorhandene Daten beim Anhängen zu erhalten, auch wenn die neue Nutzlast leer ist.
Warum wurde die Zieldatei nicht erstellt? Prüfe, ob das übergeordnete Verzeichnis existiert und der Prozess dort Schreibberechtigungen hat. Ein relativer Pfad wird ausgehend vom aktuellen Arbeitsverzeichnis des Prozesses aufgelöst. Behandle relevante OSError-Fehler im Anwendungscode. Außerdem kann ein Schreibvorgang oder das Schließen der Datei noch fehlschlagen, obwohl sie erfolgreich geöffnet wurde.