Abschnitt 11 · Lektion 2
Eine Textdatei lesen
Fast alles, was dir im Alltag Arbeit macht, kommt als Datei. Eine Liste aus der Notiz-App, ein Export aus dem Online-Banking, eine Tabelle von der Kollegin. In Dateien überleben Daten, auch wenn das Programm längst beendet ist und erst morgen wieder läuft.
Seit Lektion 5.3 steht in vielen Aufgaben ganz oben eine Zeile, die eine Datei liest,
Path("ausgaben.txt").read_text(encoding="utf-8").splitlines(). Hier geht es darum, was darin
steckt.
Öffnen, lesen, schließen
Brot
Käse
Milch with open("einkauf.txt", encoding="utf-8") as datei:
inhalt = datei.read()
print(inhalt)
print(repr(inhalt)) open("einkauf.txt", encoding="utf-8") öffnet die Datei und gibt ein Dateiobjekt (file object)
zurück. Darüber liest man aus ihr. Mit with … as datei: bekommt es einen Namen, und datei.read()
liefert den ganzen Inhalt als einen einzigen Text.
In der zweiten Ausgabe steht dieser Text mit repr(), und da siehst du, was in der ersten
unsichtbar ist. Am Ende jeder Zeile steht ein \n, auch hinter der letzten. Die leere Zeile in der
Mitte besteht aus nichts als diesem Umbruch. Die Leerzeile unter Milch kommt vom \n am Ende des
Textes plus dem Umbruch von print.
Am Ende des eingerückten Blocks wird die Datei durch das with wieder geschlossen. Das klingt nach
Ordnung um der Ordnung willen, hat aber Folgen. Unter Windows lässt sich eine geöffnete Datei weder
löschen noch umbenennen. Und wenn man in eine Datei schreibt, ohne sie zu schließen, steht der
Inhalt womöglich noch gar nicht darin.
Ohne with müsste man datei.close() selbst aufrufen, und zwar auch dann, wenn zwischendurch ein
Fehler auftritt. Mit with passiert das von selbst, auch nach einem Fehler. Deshalb öffnet man
Dateien eigentlich immer so.
Zeile für Zeile
Brot
Käse
Milch with open("einkauf.txt", encoding="utf-8") as datei:
for zeile in datei:
print(zeile) Eine for-Schleife über das Dateiobjekt liefert eine Zeile nach der anderen. Bei einer Datei mit
zehntausend Zeilen ist das angenehm, weil nie die ganze Datei im Speicher liegt. Die Ausgabe hat
aber Lücken. Jede Zeile bringt ihr \n mit, print hängt noch eins an, und so steht unter jeder
Zeile eine leere.
Brot
Käse
Milch with open("einkauf.txt", encoding="utf-8") as datei:
for zeile in datei:
print(repr(zeile), end=" ")
zeile = zeile.strip()
if zeile:
print("-", zeile)
else:
print("(leer)") Vorn steht jede Zeile mit repr(), so wie sie aus der Datei kommt, etwa 'Brot\n'. strip() nimmt
den Umbruch weg und dazu Leerzeichen am Rand. Danach ist die leere Zeile ein leerer Text, und weil
der als falsch gilt, erkennt das if sie daran.
Die Reihenfolge ist dieselbe wie beim Einkaufszettel. Erst putzen, dann prüfen. Eine Zeile aus drei
Leerzeichen ist vor dem strip() nicht leer.
Die Zeile aus den Aufgaben ist die Kurzform von alldem.
Path("einkauf.txt").read_text(encoding="utf-8") öffnet, liest alles und schließt wieder, in einem
Aufruf. Danach zerlegt splitlines() den Text in eine Liste von Zeilen, und zwar ohne die Umbrüche.
Für eine Datei, die bequem in den Speicher passt, ist das der kürzeste Weg. Ausführlich kommt Path
in Lektion 11.4.
Die Kodierung
Brot
Käse
Milch with open("einkauf.txt", encoding="cp1252") as datei:
print(datei.read()) In einer Datei stehen Bytes, also Zahlen, und noch gar keine Buchstaben. Welche Zahl welcher
Buchstabe ist, legt die Kodierung (encoding) fest. Heute schreibt fast jedes Programm UTF-8, und
darin braucht ein ä zwei Bytes. Liest man dieselbe Datei mit einer anderen Kodierung, wird jedes
der beiden Bytes ein eigenes Zeichen, und aus Käse wird Käse. Im Beispiel ist das mit cp1252
nachgestellt, der alten Kodierung von Windows.
Und genau die hat Python unter Windows bis Version 3.14 genommen, wenn man nichts angibt. Dasselbe
Programm liest dann auf dem Mac Käse und auf dem Windows-Rechner nebenan Käse, ohne jede
Fehlermeldung. Erst ab Python 3.15 gilt überall UTF-8, und bis das auf jedem Rechner läuft, dauert
es noch Jahre.
Deshalb steht in diesem Kurs überall encoding="utf-8", auch da, wo es auf dem eigenen Rechner ohne
ginge. Ohne die Angabe läuft ein Programm nur so lange, bis es jemand auf einem anderen Rechner
startet.
Wenn die Datei nicht da ist
Brot
Käse
Milch from pathlib import Path
print("Gesucht wird in", Path.cwd())
with open("einkaufsliste.txt", encoding="utf-8") as datei:
print(datei.read()) Die Datei heißt einkauf.txt, gesucht wird aber einkaufsliste.txt. Das Programm endet mit
FileNotFoundError: [Errno 2] No such file or directory: 'einkaufsliste.txt'. Die Nummer hinter
Errno ist die Fehlernummer des Betriebssystems, und 2 heißt „gibt es nicht“.
In der ersten Zeile steht, wo gesucht wurde. Ein Dateiname ohne Ordner davor gilt im
Arbeitsverzeichnis, also in dem Ordner, in dem das Programm gestartet wurde. Hier ist das
/vercel/sandbox/lern.
Wenn der Name richtig dasteht und die Meldung trotzdem kommt, wurde das Programm fast immer aus einem anderen Ordner gestartet, als du denkst. Wie man das loswird, steht in der Lektion über Pfade.
Was die Aufgabe will
Eine Tagesordnung für die Mitgliederversammlung, getippt in der Notiz-App, mit Leerzeilen und Leerzeichen, wo sie gerade hingefallen sind. Für die Einladung soll jeder Punkt eine Nummer bekommen. Die Datei liest diesmal dein Programm selbst, in der langen oder der kurzen Form.
Zum Mitnehmen
Mit with open("einkauf.txt", encoding="utf-8") as datei: wird eine Datei geöffnet und am Ende des Blocks wieder geschlossen, auch nach einem Fehler. read() holt den ganzen Text auf einmal. Eine for-Schleife über die Datei liefert eine Zeile nach der anderen, jede noch mit ihrem Zeilenumbruch am Ende, und den entfernt strip().
Jetzt du
Basis Konto, kostenlosZu dieser Lektion gehört eine Aufgabe. Du schreibst den Code selbst, und nach jedem Lauf sagt dir eine Prüfliste, was schon stimmt.
Dafür brauchst du das Basis Konto. Es kostet nichts, und ein Passwort gibt es auch nicht.
In diesem Kurs läuft dein Code auf einem Server. Dafür hat das Basis Konto 1 Stunde im Monat, mehr Zeit gibt es mit dem Premium Konto.
Was in dieser Lektion steckt
-
Artikel mit 5 Beispielen zum Ausprobieren
Steht hier, ohne Konto lesbar.
-
Aufgabe, dein Code läuft auf einem Server
Öffnet sich mit dem Basis Konto.