Python Tutorial, Teil 8 Lesen und schreiben von Dateien mit Py

Autor / Redakteur: Dipl. -Ing. Thomas Drilling / Stephan Augsten |

Früher oder später kommt für jeden Entwickler der Punkt, an dem er das Schreiben und Lesen von Dateien umsetzen möchte. Wie dies unter Python funktioniert, ist Kernthema dieses achten Teils unseres Tutorials.

Anbieter zum Thema

In jeder Programmiersprache muss man sich eher früher als später mit dem Auslesen und Schreiben von Dateien beschäftigen.
In jeder Programmiersprache muss man sich eher früher als später mit dem Auslesen und Schreiben von Dateien beschäftigen.
(Bild: Python.org)

In jeder Programmiersprache muss und möchte man Dateien von einem persistenten Datenträger lesen bzw. auf diesen schreiben. Python unterstützt dies durch eine ganze Reihe von Modulen. Zur Erinnerung: unabhängig von der verwendeten Programmiersprache besteht der Inhalt einer Datei aus einer eindimensionalen Liste von in Byte-Blöcken gruppierten Bits.

Zumindest ist dies die vereinfachte Sicht der Entwicklungsumgebung bzw. des Betriebssystems, auf dem diese ausgeführt wird. Aus Sicht eines Programmierers ist dabei bedeutsam, dass diese Art Bit-Aneinanderreihung erst im Kontext des Betriebssystems oder Anwenderprogramms (welches wir z. B. gerade erstellen) die gewünschte „Bedeutung“ erhält – also ob es sich um eine Text-, Bild- oder vielleicht auch Videodatei handelt.

Um Daten aus einer Datei in die aktuelle Session einzulesen, muss diese zunächst zum Lesen geöffnet werden. Bei Python kann man das dank der umfangreichen Standardbibliothek von Haus aus mit Hilfe der Funktion „open()“ erledigen. Genau genommen erzeugt die Funktion open() ein Dateiobjekt und liefert einen Zeiger auf dieses Objekt als Ergebnis zurück. Die Funktion benötigt dazu zwei Parameter, einen Dateinamen (ggf. mit vollständigen Pfad) und einen optionalen Modus.

open(dateiname,modus)

So öffnet folgendes Beispiel die Datei „dev-insider.txt“ ausschließlich zum Lesen („r“).

fileobject1 = open("dev-insider.txt", "r")

Da der ReadOnly-Modus die Default-Einstellung ist, kann man das „r“ auch weglassen. Nach dem „Verarbeiten“ der Datei innerhalb von Python muss die Datei mit der Methode close() stets wieder geschlossen werden:

fileobject1.close()

Beim Programmieren kommt es oft einem zeilenweisen Bearbeiten einer Datei. Folgendes Beispiel demonstriert das Vorgehen, wobei jede Zeile mit print zur Kontrolle ausgegeben wird. Etwaige Leerzeichen und Newlines lassen sich vom rechten Rand aus mit der String-Methode rstrip() entfernen.

fileobject1 = open("dev-insider.txt")
for line in fileobject1:
   print(line.rstrip())
fileobject1.close()

Ähnlich einfach ist das Schreiben in einer Datei. Der Unterschied besteht nur darin, dass das zweite Argument beim Öffnen der Datei jetzt zwingend „w“ sein muss. Für das Schreiben selbst kommt die Methode „write“ zum Einsatz:

fileobject-in = open("dev-insider.txt")
fileobject-out = open("dev-insider.txt.txt","w")
n = 1
for line in fileobject-in:
   print(line.rstrip())
   fileobject-out.write(str(i) + ": " + line)
   n = n + 1
fileobject-in.close()
fileobject-out.close()

Auf keinen Fall darf man die close()-Methode vergessen, damit die Daten in der Datei konsistent bleiben. Es bedarf dieser Anweisung, um Datei-Objekte ordnungsgemäß zu schließen.

Komplettes Einlesen eines Dateiinhalts.
Komplettes Einlesen eines Dateiinhalts.
(Bild: Drilling)

Nicht immer wird man Dateien z. B. in einer Schleife Zeile für Zeile verarbeiten. Nicht selten möchte der Programmierer eine Datei in eine komplette Datenstruktur einlesen, etwa einen String oder eine Liste. So kann die Datei unmittelbar wieder geschlossen werden und man arbeitet im Programmcode lediglich auf der Datenstruktur weiter. Das könnte z. B: so funktionieren:

>>> fileobject2 = open("dev-insider.txt").readlines()
>>> print(fileobject2)

Die Ausgabe sieht dann so aus wie in der vorangestellten Abbildung. Optional kann aber auch die read-Methode der Funktion open() verwenden. Hierbei würde die komplette Datei in einen String eingelesen:

>>> fileobject3 = open("dev-insider.txt").read()

Die read-Methode der Funktion open() behandelt den Dateiinhalt als String.
Die read-Methode der Funktion open() behandelt den Dateiinhalt als String.
(Bild: Drilling)

Man kann dann gezielt bestimmte „Positionen“ ausgeben, wie in dieser Abbildung zu sehen ist. Die Befehle lauten:

>>> print(fileobject3[3:35])

Der Typ des Fileobjects ist dann „str“, wie …

>>> type(fileobject3)

zweifelsfrei bestätigt:

Das pickle-Modul

Das manuelle Speichern von Programm-Daten in einer Datei ist nicht unbedingt die empfehlenswerteste Methode zum Erzeugen persistenter Daten; der Programmierer müsste dann nämlich die vollständige Serialisierung der Daten selbst erledigen. Python bietet daher verschiedene Module, mit denen sich persistente Programmdaten einfacher generieren lassen, wie z. B. das pickle-Modul, das marshal-Modul und das shelve-Modul.

Der englische Begriff „to pickle“ bedeutet einlegen oder pökeln. Im Zusammenhang mit Programmiersprachen im Allgemeinen bzw. Python im Speziellen ist damit gemeint, Python-Objekte zu „konservieren“. So lassen sie sich zu einem späteren Zeitpunkt – etwa in einer anderen Sitzung oder bei anderen Programmläufen – wieder einlesen und verwenden, da Arbeitsspeicher flüchtig ist. Letztendlich bedeutet das nichts anderes, als das persistente Abspeichern z. B. in einer Datei.

Python-Tutorial
Bildergalerie mit 10 Bildern

Das pickle-Modul bietet gegenüber der oben gezeigten Methode den Vorteil, dass sich der Programmierer nicht um das Serialisieren der Objekte beim Speichern kümmern muss. Das Modul speichert die Daten exakt so ab, dass sie bei Bedarf jederzeit wieder deserialisiert werden können, etwa mit der Methode „dump“. Die allgemeine Syntax ist:

pickle.dump(object, filename[, protocol, *, fix_imports=True])

Konkret schreibt dump() eine Abbildung des Objektes „object“ in das Dateiobjekt „filename“. Die Argumente in den eckigen Klammern sind optional. Das Argument „protocol“ kann dabei zur Steuerung der Ausgabe-Art benutzt werden. Das von pickle verwendete Datenformat ist Python-spezifisch. Dies hat den Vorteil, dass keine Einschränkungen durch externe Standards wie XDR (die z. B. keine Pointer-Sharing darstellen kann) auferlegt werden. Auf der anderen Seite bedeutet das, dass Nicht-Python-Programme möglicherweise nicht in der Lage sind, „gepickelte“ Python-Objekte zu rekonstruieren.

Die einzelnen Protokollversionen haben folgende Bedeutung:

  • 0 … ist die ursprüngliche Ablageart von Python, vor der Einführung von Python3, ein für Menschen gut lesbares Format und voll abwärtskompatibel mit älteren Python-Versionen.
  • 1 … verwendet dagegen das alte Binärformat und ist ebenfalls abwärtskompatibel mit älteren Python-Versionen.
  • 2 … wurde mit Python 2.3 eingeführt und ermöglicht im Wesentlichen ein effizienteres "Pickling".
  • 3 … wurde mit Python 3.0 eingeführt und stellt einen besonders kompakten Byte-, bzw. Binär-Modus zur Verfügung. Dieser stellt ab Python 3.0 den Default-Modus dar, auch wenn im Modus 3 erzeugte Dateien nicht mehr mit dem pickle-Modul von Python 2.x bearbeitet werden können.

Das Modul „Picktools“ enthält übrigens eine Reihe von Werkzeugen zum Analysieren von Datenströmen, die durch das pickle-Modul erzeugt werden. Zur Wahrung der Abwärtskompatibilität in Python 3 könnte man zudem den Parameter „fix_imports“ auf true setzen, wodurch Python stets einen Wert kleiner 3 erzwingt und das pickle-Modul versucht, die neuen Modul-Namen von Python 3 in den alten Modul-Namen von Python 2, abzubilden, damit die „gepickelten“ Daten auch in Python 2 gelesen werden können. Ein Beispiel für das Verwenden des pickle-Moduls mit der dump-Methode könnte so aussehen:

>>> import pickle
>>> vogelbusiness = ["dev-insider.de", "storage-insider.de", "datacenter-insider.de”]
>>> fileobject5 = open("dataobject.pkl","bw")
>>> pickle.dump(vogelbusiness,fileobject5)
>>> fileobject5.close()

Die pickle-Methode dump() schreibt die einem Objekt zugeordneten Daten in eine Datei.
Die pickle-Methode dump() schreibt die einem Objekt zugeordneten Daten in eine Datei.
(Bild: Drilling)

Hier öffnet „fileobject5 = open("dataobject.pkl","bw")“ die Datei „dataobject.pkl“ zum Schreiben im Byte-Modus („bw“) und „pickle.dump(vogelbusiness,fileobject5)“ schreibt dann die Daten aus dem Objekt „vogelbusiness“ in die Datei. Solche mit „pickle.dump“ geschrieben Daten lassen sich mit der pickle-Methode „pickle.load(file)“ jederzeit wieder einlesen, wobei „pickle.load“ automatisch erkennt, in welchem Format eine Datei erstellt wurde.

Die mittels dump() erstellte Datei wird wieder eingelesen.
Die mittels dump() erstellte Datei wird wieder eingelesen.
(Bild: Drilling)

Das Einlesen der dataobject.pkl in Python könnte jetzt zwar exemplarisch im gleichen Programm, bzw. der gleichen Session erfolgen, in der Praxis wird dies aber wohl eher in einem erneuten Programmlauf oder aus einem anderen Programm heraus passieren:

>>> import pickle
>>> fileobject6 = open("dataobject.pkl","rb")
>>> vogelbusinesstitel = pickle.load(fileobject6)
>>>fileobject6 (close)
>>> print(vogelbusinesstitel)
['dev-insider.de', 'storage-insider.de', 'datacenter-insider.de']
>>>

In den letzten beiden Teilen 9 und 10 unserer Python-Einführung wenden wir uns zunächst dem Lambda-Operator zu und befassen uns dann noch einmal konkreter mit Klassen, Objekten, Vererbung und Methoden, also dem objektorientierten Programmierschema.

Python-Tutorial
Bildergalerie mit 10 Bildern

(ID:45358909)