Link Search Menu Expand Document

Input/Output

Dateizugriff

Daten sind in den allermeisten Fällen nicht im Programm selbst gespeichert, sondern werden auf externen Speichern vorgehalten. Dateien sind hier der häufigste Fall für die Datenspeicherung, sodass wir uns diese zuerst ansehen.

Ein Programm braucht eine Möglichkeit, mit Dateien zu interagieren. Hierzu verwendet Python das Konzept von Dateiobjekten, d. h. Objekten, die im Programm benutzt werden können, deren Methoden aber Daten mit der Datei austauschen. Das Dateiobjekt ist somit ein Stellvertreter der Datei im Programm.

  • Lesen und Schreiben in Dateien wird über Dateiobjekte (file objects) realisiert
  • Sie werden über open() oder file() angelegt
  • Dateien, müssen mit close() wieder geschlossen werden

Das Öffnen einer Datei, d. h. die Vorbereitung für die Interaktion, reserviert im Betriebssystem Ressourcen und Speicher. Je nach Betriebssystem wird die Datei auch für Zugriffe durch Andere gesperrt, solange sie geöffnet ist. Um die Ressourcen und Sperren wieder freizugeben, muss man eine Datei nach der Benutzung schließen.

Wird eine Datei nicht geschlossen, kann es zu Engpässen beim Speicher kommen und im schlimmsten Fall gehen Daten verloren.

Open

Eine Datei wird mit der open()-Funktion geöffnet. Dieser Funktion muss man zum einen den Dateinamen übergeben und zum anderen anzeigen, was man mit der Datei machen möchte (options). Die Syntax mit den Buchstaben und dem Pluszeichen für die Angabe der Optionen stammt aus der Urzeit des Computers und wurde in den 1970er Jahren bei der Programmiersprache C so definiert, ist also historisch gewachsen.

f = open(filename, options)

  • filename: Pfad zu der Datei
  • options: Optionen
Option Bedeutung
'r' Datei lesen
'w' Datei schreiben (wird vorher gelöscht)
'x' Datei anlegen und zum Schreiben öffnen
'a' An Ende der Datei anhängen
'r+' Datei lesen und schreiben
'w+' Datei lesen und schreiben (wird vorher gelöscht)
'a+' Lesen und Schreiben am Ende der Datei
'b' Binärmodus
't' Textmodus (Standard)

Wenn man eine Datei mit w öffnet und es gibt die Datei bereits, dann wird der Inhalt der Datei gelöscht und man fängt wieder am Anfang der Datei an. Andernfalls wird die Datei angelegt.

Sollen alten Daten erhalten bleiben und die neuen ans Ende angehängt werden, muss man die Option a verwenden.

Wenn Sie die Option x verwenden, dann bricht open() mit einem Fehler ab, falls die Datei bereits existiert. Es stellt also sicher, dass Sie nicht aus Versehen eine Datei überschreiben, die bereits existiert.

Etwas trickreich sind die Optionen b und t, die mit den anderen kombiniert werden. Eine Datei kann von Python entweder im Textmodus (Option t) oder im Binärmodus (Option b) geöffnet werden. Im Textmodus macht Python automatische Konvertierungen zwischen Zeichensätzen und andere Anpassungen, die für Textdateien sinnvoll sind. Bearbeitet man allerdings im Textmodus eine Binärdatei (z. B. ein Bild), dann gehen die Daten mit großer Wahrscheinlichkeit kaputt. Deswegen muss man Dateien, die keine Textdateien sind, explizit mit der Option b öffnen, da t der Standardwert ist, wenn keine der beiden Optionen angegeben wird.

f = open('myfile.txt', 'rt')

# Datei verarbeiten

f.close()

Das Beispiel zeigt, wie man eine Datei zum Lesen öffnet. Die Verarbeitung der Daten ist hier ausgelassen und wird weiter unten gezeigt.

With

Das Schließen einer geöffneten Datei ist eine wichtige Operation, die man nicht vergessen sollte. Damit auch in komplexen Programmen das close zum open nicht vergessen wird, gibt es in Python die Möglichkeit mit dem with-Statement eine Reihe von Statements zu definieren, nach deren Abschluss die geöffnete Ressource (hier also Datei) wieder geschlossen wird. Allgemein ist die Syntax von with:

with EXPR as VAR:
    STMTS
    ...

Hierbei wird der Ausdruck EXPR ausgeführt und das Ergebnis wird der Variable VAR zugewiesen. Wenn die Statements STMTS abgearbeitet sind, wird automatisch eine Methode ausgeführt, welche die Ressourcen schließt, die EXPR geöffnet hat. Wie das genau funktioniert, würde hier zu weit führen – aber es funktioniert.

  • with-Statement stellt sicher, dass die Datei korrekt wieder geschlossen wird
  • kein close mehr nötig
with open('myfile.txt', 'r') as f:
    # Datei verarbeiten

# f wird automatisch geschlossen, wenn with verlassen wird

Durch die Verwendung von with in dem Code-Beispiel muss kein close() mehr für die Datei f aufgerufen werden. Dies passiert automatisch.

Binärdaten in Python

Da Dateien auch Binärdaten enthalten können, stellt sich die Frage, wie man diese in Python darstellen kann. Hierzu dienen die beiden Klassen bytes und bytearray.

Binärdaten

  • werden durch bytes- und bytearray-Objekte repräsentiert
  • bytes
    • können als Literal mit b"" oder b'' angegeben werden
      z. B. bs = b"binaerdaten"
    • Literale dürfen nur ASCII-Zeichen enthalten
    • sind unveränderlich
  • bytarray
    • sind veränderlich
    • werden über bytearray() erzeugt
Beispiel: Verwalten von Binärdaten
b = b"binaerdaten"
ba = bytearray(b)
print(b.hex()) # -> 62696e616572646174656e
print(ba.hex()) # -> 62696e616572646174656e

print(str(b)) # -> "b'binaerdaten'"
print(str(ba)) # -> "bytearray(b'binaerdaten')"

Ein Byte entspricht einer Zahl im Wertebereich 0–255. Damit lässt sich jedes Byte durch eine zweistellige Hexadezimalzahl (Basis 16) darstellen. Die hex()-Methode von byte und bytearray macht genau das und gibt den Inhalt als Folge von Hexadezimalziffern aus. Hierbei entsprechen immer zwei Ziffern einem Byte.

Lesen aus Datei

Nachdem eine Datei geöffnet ist, muss man mit den Daten in der Datei interagieren. Hierzu bietet Python eine ganze Reihe von Methoden an, die man auf dem Dateiobjekt (Rückgabewert von open()) aufrufen kann.

Da man häufig Textdateien verarbeitet, bietet es sich an, diese Dateien zeilenweise zu verarbeiten, sodass hierfür Methoden vorhanden sind.

  • read(n) – Liest n Bytes/Zeichen ein und gibt String zurück
  • readline() – Liest pro Aufruf eine Zeile
  • readlines() – Liest die ganze Datei in eine Liste von Zeilen
  • for line in f: – Liest ebenfalls zeilenweise als Schleife
with open('myfile.txt', 'r') as f:
    for line in f:
        print(line)

Wenn die Datei in einem Binärformat ist, dann können Sie nur die read()-Methode benutzen, da die Methoden für das zeilenweise Lesen keinen Sinn ergeben.

Wenn man read() ohne Parameter aufruft, dann wird die gesamte Datei eingelesen und zurückgegeben. Dasselbe passiert bei read(-1).

Denken Sie daran, dass der Speicher des Computers endlich ist und eine Datei durchaus größer sein kann. Deshalb muss man die Methoden read() und readlines() bei großen Dateien mit Vorsicht verwenden.

Schreiben in Datei

Analog zu den Methoden zum Lesen gibt es auch Methoden zum Schreiben in eine Datei. Die wichtigste ist die write()-Methode, die einen String nimmt und in die Datei schreibt.

  • write(s) schreibt den String s in eine Datei
  • truncate leert die Datei
  • seek(pos) springt an eine Position in der Datei
  • tell() liefert die aktuelle Position
name = "Thomas"
with open('hello.txt', 'w') as f:
    f.truncate()
    print(f.tell()) # -> 0
    f.write("Hello, {}!\n".format(name))
    f.write("Genug der Tollerei")
    print(f.tell()) # -> 33

Das Beispielprogramm erzeugt folgende Datei:

hello.txt
Hello, Thomas!
Genug der Tollerei

Die Zeilenenden muss man selbst ausgeben (\n), da die write()-Aufurufe einfach aufeinanderfolgend in die Datei schreiben.

Bei der Arbeit mit Binärdateien kommt bei Python kein normaler String zum Einsatz, sondern ein bytes-Objekt.

with open('hello.txt', 'wb') as f:
    f.write(b"Hello, Thomas!\n")
    f.write(b"Genug der Tollerei")

Das Ergebnis ist in diesem Fall identisch mit dem vorhergehenden Beispiel, weil der Text nur ASCII-Zeichen enthält. Das ändert sich, wenn man Zeichen außerhalb des ASCII verwendet.

with open('non-ascii.txt', 'w') as f:
    f.write("Sonderzeichen äöüß\n")

with open('non-ascii.txt', 'rb') as f:
    b = f.read()
    print(b) # -> b'Sonderzeichen \xc3\xa4\xc3\xb6\xc3\xbc\xc3\x9f\n'

Man sieht, dass die Sonderzeichen im UTF-8-Format codiert werden und jedes Zeichen durch zwei Bytes repräsentiert wird.

Lesen von der Console

Die Funktion input(prompt) erlaubt es, Eingaben von der Konsole zu Lesen

name = input("Wie heisst Du?: ")
print("Hallo {}".format(name))
Ausgabe
Wie heisst Du?: Thomas
Hallo Thomas

Lesen von Kommandozeilenargumenten

Man kann Programmen bei deren Aufruf auf der Kommandozeile sogenannte Argumente bzw. Kommandozeilenargumente mitgeben. Wenn Sie z. B. Ihr Python-Programm mit python myprog.py starten, dann übergeben Sie dem Programm python das Kommandozeilenargument myprog.py.

Wenn man das Modul sys importiert, dann finden sich in der Liste sys.argv die Kommandozeilenargumente, die dem Skript übergeben wurden.

  • Kommandozeile ist weitere Quelle von Eingaben
  • Liste sys.argv (Modul sys) liefert die Argumente
arg_reader.py
import sys
a0 = sys.argv[0] # Name des Skripts
a1 = sys.argv[1] # 1. Argument
a2 = sys.argv[2] # 2. Argument
a3 = sys.argv[3] # 3. Argument

print(a0, a1, a2, a3)
Ausgabe
$ python3 arg_reader.py Argument1 Argument2 Argument3

arg_reader.py Argument1 Argument2 Argument3

Per Konvention steht im ersten Element (Index 0) der Argumentliste bei allen Programmiersprachen der Name des Programms, das aufgerufen wurde. Die Kommandozeilenargumente folgen dann in den folgenden Listenelementen.


Copyright © 2022 Thomas Smits