NB02_Lesen_und_Schreiben_von_Dateien

(c) 2019/2020 Hochschule Augsburg - Fakultät für Informatik - Prof.Dr.Nik Klever

Builtin-Funktion open()

Die Builtin-Funktion open() wird im allgemeinen mit zwei Argumenten filename und mode aufgerufen. Dabei ist filename der Name der Datei, genauer gesagt, der Pfadname der Datei, die geöffnet werden soll. Und mode ist der Modus, d.h. ob die Datei lesend (mode=r) oder schreibend (mode=w, wenn die Datei neu erstellt wird bzw. überschrieben wird oder mode=a, wenn an die Datei angehängt wird) geöffnet werden soll. Der Rückgabewert dieser Funktion ist ein Dateiobjekt.

Schreiben einer Datei

Funktion open() zum Schreiben

Mit dem folgenden Ausdruck wird die Datei textdatei.txt zum Schreiben neu erstellt, bzw. wenn diese Datei bereits existiert, überschrieben:

In [2]:
wd = open("textdatei.txt","w")

Der Rückgabewert der Funktion open ist ein Dateiobjekt, welches in diesem Fall in der Variablen wd abgespeichert wird. Ein Dateiobjekt kann die Funktion write benutzen, um Zeichenketten in die Datei zu schreiben.

Funktion write()

Entsprechende andere Objekte, wie z.B. Integer- oder Float-Zahlen müssen erst mit der str-Funktion in eine Zeichenkette umgewandelt werden. Der Rückgabewert der Funktion write ist die Anzahl der Zeichen, die in die Datei geschrieben worden sind.

Wichtig: Unterschied zur Funktion print()

Wichtig zu wissen ist, dass bei der Funktion write() der Programmierer - im Gegensatz zur Funktion print() - selbst Zeilenumbrüche (mittels dem Zeilenumbruch-Zeichen "\n") an entsprechend geeigneten bzw. notwendigen Stellen anhängen muss! Dies kann über einen eigenen Aufruf write("\n") geschehen, aber auch über das Anhängen (oder Voranstellen) eines Zeilenumbruchs an die Zeichenkette +"\n".

In [3]:
a = """Dies ist ein mehrzeiliger Text
mit vier Zeilen ohne Zeilenende-Zeichen
und einfachen "Hochkommas" innerhalb der Zeichenkette,
die dann nicht maskiert werden müssen"""
In [4]:
wd.write(a)
Out[4]:
163
In [5]:
wd.write("\n")
Out[5]:
1
In [6]:
b = 87.467
In [7]:
wd.write("\n"+str(b)+"\n")
Out[7]:
8
In [8]:
c = "Alternativ kann ein mehrzeiliger Text\nauch mit Zeilenende-Zeichen\nversehen werden, um\nein Zeilenende zu markieren"
In [9]:
wd.write(c)
Out[9]:
113

Schliessen einer Datei - Funktion close()

Wenn alle Datensätze in die Datei geschrieben worden sind, dann muss die Datei mit der Funktion close geschlossen werden. Ansonsten könnte ein unkontrollierter Zustand bzw. auch Verlust der bisher geschriebenen Daten in die Datei geschehen.

In [10]:
wd.close()

Lesen einer Datei

Funktion open() zum Lesen

Mit dem folgenden Aufruf der Funktion open wird die Datei textdatei.txt zum Lesen geöffnet:

In [11]:
rd = open("textdatei.txt","r")

Funktion read()

Über die Funktion read() wird die gesamte Datei eingelesen und der Inhalt der Datei als Rückgabewert zurückgegeben - allerdings besitzt die Funktion read auch noch einen Parameter size, der als Argument übergeben werden kann und angibt, wieviele Bytes gelesen werden sollen. Wenn dieser Parameter nicht angegeben wird (oder negativ ist), dann wird die gesamte Datei eingelesen.

In [12]:
inhalt = rd.read()
In [13]:
print(inhalt)
Dies ist ein mehrzeiliger Text
mit vier Zeilen ohne Zeilenende-Zeichen
und einfachen "Hochkommas" innerhalb der Zeichenkette,
die dann nicht maskiert werden müssen

87.467
Alternativ kann ein mehrzeiliger Text
auch mit Zeilenende-Zeichen
versehen werden, um
ein Zeilenende zu markieren

Wenn alle erforderlichen Daten aus der Datei gelesen worden sind, dann sollte die Datei wieder mit der Funktion close geschlossen werden. Ansonsten könnte die Datei in einen unkontrollierten Zustand geraten, wobei die Leseoperation unkritischer als die Schreiboperation ist.

In [14]:
rd.close()

Funktion readline()

Anstelle der Funktion read() kann auch die Funktion readline() verwendet werden, die jeweils nur eine Zeile aus der Datei einliest:

In [15]:
rd = open("textdatei.txt","r")
zeile1 = rd.readline()
print(zeile1)
zeile2 = rd.readline()
print(zeile2)
rd.close()
Dies ist ein mehrzeiliger Text

mit vier Zeilen ohne Zeilenende-Zeichen

Einlesen der gesamten Datei in einer Schleife

Um die gesamte Datei in einer Schleife einzulesen, ist der beste und effektivste Weg, direkt über das Dateiobjekt zu iterieren:

In [16]:
rd = open("textdatei.txt","r")
for zeile in rd:
    print(zeile)
rd.close()
Dies ist ein mehrzeiliger Text

mit vier Zeilen ohne Zeilenende-Zeichen

und einfachen "Hochkommas" innerhalb der Zeichenkette,

die dann nicht maskiert werden müssen



87.467

Alternativ kann ein mehrzeiliger Text

auch mit Zeilenende-Zeichen

versehen werden, um

ein Zeilenende zu markieren
In [17]:
%%Mooc StringAssessment
Out[17]:

Unterschied str - print

In dem folgenden Code wird die komplette Datei auf einmal eingelesen:



rd = open("textdatei.txt","r")
inhalt = rd.read()
print(inhalt)
rd.close()

In dem folgenden Code wird dagegen die komplette Datei Zeile für Zeile eingelesen:


rd = open("textdatei.txt","r")
for zeile in rd:
    print(zeile)
rd.close()

Der Unterschied in der Ausgabe ist, das in der print-Funktion automatisch ein Zeilenumbruch angehängt wird

Hinweis:Schauen sie sich in der offiziellen Dokumentation (s. weitere Literatur) die möglichen Argumente der print-Funktion an

Geben sie als Antwort nur die veränderte Zeile mit der print-Funktion an!

Wie können sie nun die Ausgabe in dem zweiten Code so verändern, dass die Ausgabe identisch mit der ersten Ausgabe wird ?



Vermeidung von close() mit with

In Python gibt es ein besonderes Schlüsselwort with welches generell den Beginn eines bestimmten Kontextes definiert. Im Zusammenhang mit dem Schreiben und Lesen von Dateien ist dieser Kontext das Öffnen einer Datei. Der Vorteil ist, dass mit dem Schlüsselwort with und dem Öffnen der Datei dieser Kontext durch einen Block (d.h. durch die Einrückung) beginnt und der Kontext mit der Beendigung des Blocks (d.h. durch die Ausrückung) der endet und bei Beendigung des Kontexts die Datei automatisch geschlossen wird und damit der Zustand closed des Dateiobjekts entsprechend wahr wird.

In [18]:
with open("textdatei.txt") as rd:
    inhalt = rd.read()
print(inhalt)
rd.closed
Dies ist ein mehrzeiliger Text
mit vier Zeilen ohne Zeilenende-Zeichen
und einfachen "Hochkommas" innerhalb der Zeichenkette,
die dann nicht maskiert werden müssen

87.467
Alternativ kann ein mehrzeiliger Text
auch mit Zeilenende-Zeichen
versehen werden, um
ein Zeilenende zu markieren
Out[18]:
True
In [19]:
%%Mooc StringAssessment
Out[19]:

with

Welches Ergebnis wird angezeigt, wenn die folgenden Statements ausgeführt werden:



with open("textdatei.txt") as rd:
    print(rd.closed)

Welches Ergebnis wird angezeigt?



Binär Dateien

Allgemeines

Bisher wurden nur Textdateien betrachtet, aber natürlich gibt es auch Dateien - wie z.B. Bilddateien - die nicht aus Texten bzw. Zeichenketten bestehen, sondern ganz allgemein aus beliebigen Bytes. Hierzu kann in Python an das mode-Argument in der open-Funktion ein b angehängt werden. Zudem gibt es noch ein weiteres Mode-Anhängsel + für lesenden und schreibenden Modus, bei dem insbesondere aber der Programmierer für die korrekte Positionierung des Lese-/Schreibkopfes in der Datei verantwortlich zeichnet. Hierzu gibt es die weiteren Funktionen tell und seek.

Funktion tell()

tell() gibt die derzeitige Position des Lese-/Schreibkopfes in der Datei als Integer-Zahl zurück und repräsentiert die Anzahl der Bytes vom Beginn der Datei an (im Textmodus ist dieser Rückgabewert unklar definiert, daher wird er im Textmodus auch nicht verwendet).

In [20]:
bd = open('binärdatei.xxx','wb+')
In [21]:
bd.write(b'0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ')
Out[21]:
62

Funktion seek()

seek(offset, from_what) wird benutzt, um die Position des Lese-/Schreibkopfes in der Datei zu verändern. Die Position wird aus dem Parameter offset berechnet, ausgehend von einem entsprechenden Referenzpunkt, der durch from_what bestimmt wird. from_what=0 bedeutet von Beginn der Datei an, from_what=1 bedeutet von der derzeitigen Position ausgehend und from_what=2 bedeutet vom Ende der Datei ausgehend. Der Standardwert für from_what ist 0, also von Beginn der Datei ausgehend.

In [22]:
bd.seek(1)
Out[22]:
1
In [23]:
Null = bd.read(1)
In [24]:
print(Null)
print(Null.hex())
b'1'
31

Im folgenden Beispiel springt der Lese-/Schreibkopf zum 10ten Byte in der Datei:

In [25]:
bd.seek(10) 
Out[25]:
10
In [26]:
a = bd.read(1)
In [27]:
print(a)
print(a.hex())
b'a'
61

Im folgenden Beispiel springt der Lese-/Schreibkopf zum 26ten Byte vor dem Ende der Datei:

In [28]:
bd.seek(-26, 2)
Out[28]:
36
In [29]:
A = bd.read(1)
In [30]:
print(A)
print(A.hex())
b'A'
41
In [31]:
bd.close()
In [32]:
liste = [a,a.hex(),A,A.hex()]
liste
Out[32]:
[b'a', '61', b'A', '41']
In [33]:
%%Mooc StringAssessment
Out[33]:

ASCII Zeichen

In der obigen Datei binärdatei.xxx sind die wesentlichen Zahlen und Buchstaben der ASCII Zeichen enthalten


Geben sie die Antwort in einer Liste wie oben an

Wie lautet der Buchstabe und Hexdezimal-Code des 11ten Bytes nach dem Beginn und des 25ten Bytes vor dem Ende der Datei



In [34]:
%%Mooc Video
Out[34]:

Weitere Literatur

In [35]:
%%Mooc WebReference

Reading and Writing Files

https://docs.python.org/3/tutorial/inputoutput.html#reading-and-writing-files

Hinweis: Detaillierter Hinweise zum Lesen und Schreiben von Dateien

In [36]:
%%Mooc WebReference

Builtin Functons

https://docs.python.org/3/library/functions.html

Hinweis: Detaillierte Beschreibungen der oft benutzten Builtin-Funktionen