6.2 Daten aus einer Datei auslesen
Zunächst besprechen wir, wie Daten aus einer Datei ausgelesen werden können. Dazu müssen wir lesend auf diese Datei zugreifen. Bei der Testdatei, die wir in diesem Beispiel verwenden werden, handelt es sich um ein Wörterbuch, das in jeder Zeile ein englisches Wort und, durch ein Leerzeichen davon getrennt, seine deutsche Übersetzung enthält. Die Datei soll woerterbuch.txt heißen:
Spain Spanien
Germany Deutschland
Sweden Schweden
France Frankreich
Italy Italien
Im Programm möchten wir die Daten in dieser Datei so aufbereiten, dass wir später in einem Dictionary[ 15 ](siehe Abschnitt 3.5) bequem auf sie zugreifen können. Als kleine Zugabe werden wir das Programm noch dahingehend erweitern, dass der Benutzer das Programm nach der Übersetzung eines englischen Begriffs fragen kann.
Zunächst einmal muss die Datei zum Lesen geöffnet werden. Dazu verwenden wir die Built-in Function open. Diese gibt ein sogenanntes Dateiobjekt (engl. file object) zurück:
fobj = open("woerterbuch.txt", "r")
Als ersten Parameter von open übergeben wir einen String, der den Pfad zur gewünschten Datei enthält. Beachten Sie, dass hier sowohl relative als auch absolute Pfade erlaubt sind.[ 16 ](Ein absoluter Pfad identifiziert eine Datei ausgehend von der Wurzel im Dateisystembaum.
Unter Windows könnte ein absoluter Pfad folgendermaßen aussehen:
C:\Programme\TestProgramm\woerterbuch.txt. Ein relativer Pfad bezieht sich auf das aktuelle Arbeitsverzeichnis des Programms.
Hier kann die Verknüpfung »..« für das übergeordnete Verzeichnis verwendet werden.
Im Beispiel ist ein relativer Pfad angegeben, die Datei woerterbuch.txt muss sich also im gleichen Verzeichnis befinden wie das Programm.
) Der zweite Parameter ist ebenfalls ein String und spezifiziert den Modus, in dem die Datei geöffnet werden soll, wobei "r" für »read« steht und bedeutet, dass die Datei zum Lesen geöffnet wird. Das von der Funktion zurückgegebene Dateiobjekt verknüpfen wir mit der Referenz fobj. Sollte die Datei nicht vorhanden sein, wird ein FileNotFoundError erzeugt:
Traceback (most recent call last):
File "woerterbuch.py", line 1, in <module>
fobj = open("woerterbuch.txt", "r")
FileNotFoundError: [Errno 2] No such file or directory: 'woerterbuch.txt'
Nachdem open aufgerufen wurde, können mit dem Dateiobjekt Daten aus der Datei gelesen werden. Nachdem das Lesen der Datei beendet worden ist, muss sie explizit durch Aufrufen der Methode close geschlossen werden:
fobj.close()
Nach Aufruf dieser Methode können keine weiteren Daten mehr aus dem Dateiobjekt gelesen werden.
Im nächsten Schritt möchten wir die Datei zeilenweise auslesen. Dies ist relativ einfach, da das Dateiobjekt zeilenweise iterierbar ist. Wir können also die altbekannte for-Schleife verwenden:
fobj = open("woerterbuch.txt", "r")
for line in fobj:
print(line)
fobj.close()
In der for-Schleife iterieren wir zeilenweise über das Dateiobjekt, wobei line jeweils den Inhalt der aktuellen Zeile referenziert. Momentan wird jede Zeile im Schleifenkörper lediglich ausgegeben. Wir möchten jedoch im Programm ein Dictionary aufbauen, das nach dem Einlesen der Datei die englischen Begriffe als Schlüssel und den jeweiligen deutschen Begriff als Wert enthält.
Dazu legen wir zunächst ein leeres Dictionary an:
woerter = {}
Dann wird die Datei woerterbuch.txt zum Lesen geöffnet und in einer Schleife über alle Zeilen der Datei iteriert:
fobj = open("woerterbuch.txt", "r")
for line in fobj:
zuordnung = line.split(" ")
woerter[zuordnung[0]] = zuordnung[1]
fobj.close()
Im Schleifenkörper verwenden wir nun die Methode split eines Strings, um die aktuell eingelesene Zeile in zwei Teile einer Liste aufzubrechen: in den Teil links vom Leerzeichen, also das englische Wort, und in den Teil rechts vom Leerzeichen, also das deutsche Wort. In der nächsten Zeile des Schleifenkörpers wird dann ein neuer Eintrag im Dictionary angelegt, mit dem Schlüssel zuordnung[0] (dem englischen Wort) und dem Wert zuordnung[1] (dem deutschen Wort).
Verändern Sie einmal den oben dargestellten Code dahingehend, dass nach dem Schließen des Dateiobjekts das erzeugte Dictionary mit print ausgegeben wird. Diese Ausgabe wird etwa so aussehen:
{'Spain': 'Spanien\n', 'Germany': 'Deutschland\n', 'Sweden': 'Schweden\n',
'France': 'Frankreich\n', 'Italy': 'Italien\n'}
Sie sehen, dass hinter jedem Wert ein \n, also die Escape-Sequenz für einen Zeilenumbruch, steht. Das liegt daran, dass ein Zeilenumbruch in Python als Zeichen und damit als Teil des Dateiinhalts angesehen wird. Deswegen wird jede Zeile einer Datei vollständig, also inklusive eines möglichen Zeilenumbruchs am Ende, eingelesen. Der Zeilenumbruch wird natürlich nur eingelesen, wenn er wirklich vorhanden ist. Das bedeutet, dass die letzte Zeile (in diesem Fall Italy Italien) ohne Zeilenumbruch am Ende eingelesen wird.
Den Zeilenumbruch möchten wir im endgültigen Dictionary nicht wiederfinden. Aus diesem Grund rufen wir in jedem Schleifendurchlauf die strip-Methode des Strings line auf. Diese entfernt alle Whitespace-Zeichen[ 17 ](Whitespaces sind Zeichen, die am Bildschirm typischerweise nicht dargestellt werden. Beispiele für Whitespaces sind Leerzeichen, Tabulatorzeichen oder Zeilenumbrüche. Näheres zu Whitespaces erfahren Sie in Abschnitt 13.4.2, »String-Methoden«. ), unter anderem also einen Zeilenumbruch, am Anfang und Ende des Strings.
woerter = {}
fobj = open("woerterbuch.txt", "r")
for line in fobj:
line = line.strip()
zuordnung = line.split(" ")
woerter[zuordnung[0]] = zuordnung[1]
fobj.close()
Damit ist der Inhalt der Datei vollständig in ein Dictionary überführt worden. Als kleine Zugabe möchten wir es dem Benutzer ermöglichen, Übersetzungsanfragen an das Programm zu senden. Im Ablaufprotokoll soll das folgendermaßen aussehen:
Geben Sie ein Wort ein: Germany
Das deutsche Wort lautet: Deutschland
Geben Sie ein Wort ein: Italy
Das deutsche Wort lautet: Italien
Geben Sie ein Wort ein: Greece
Das Wort ist unbekannt
Im Programm lesen wir in einer Endlosschleife Anfragen vom Benutzer ein. Mit dem in-Operator prüfen wir, ob das eingelesene Wort als Schlüssel im Dictionary vorhanden ist. Ist das der Fall, wird die entsprechende deutsche Übersetzung ausgegeben. Sollte das eingegebene Wort nicht vorhanden sein, wird eine Fehlermeldung ausgegeben.
woerter = {}
fobj = open("woerterbuch.txt", "r")
for line in fobj:
line = line.strip()
zuordnung = line.split(" ")
woerter[zuordnung[0]] = zuordnung[1]
fobj.close()
while True:
wort = input("Geben Sie ein Wort ein: ")
if wort in woerter:
print("Das deutsche Wort lautet:", woerter[wort])
else:
print("Das Wort ist unbekannt")
Das hier vorgestellte Beispielprogramm ist weit davon entfernt, perfekt zu sein, jedoch zeigt es sehr schön, wie Dateiobjekte und auch Dictionarys sinnvoll eingesetzt werden können. Fühlen Sie sich dazu ermutigt, das Programm zu erweitern. Sie könnten es dem Benutzer beispielsweise ermöglichen, das Programm ordnungsgemäß zu beenden, Übersetzungen in beide Richtungen anbieten oder das Verwenden mehrerer Quelldateien erlauben.
[»] Hinweis
Sie werden in Kapitel 24, »Kontextobjekte«, die with-Anweisung kennenlernen, mit deren Hilfe Sie das Öffnen und Schließen einer Datei eleganter schreiben können:
with open("woerterbuch.txt", "r") as fobj:
# Ihre Dateioperationen auf fobj
pass
Der Vorteil ist, dass das Dateiobjekt nicht mehr explizit geschlossen werden muss. Wählen Sie hier ganz nach Ihren Vorlieben, welche Variante Ihnen besser gefällt.