4. Unterrichtsblock

Dateipfade
Programme speichern Notenlisten, Einstellungen oder Logdateien. Damit Python eine Datei findet, braucht es ihren Pfad. Für Pfade gibt es das Modul pathlib: Ein Path ist ein Pfad, mit dem man rechnen kann.
| Ausdruck | liefert |
|---|---|
Path.cwd() | Arbeitsverzeichnis: der Ordner, aus dem python gestartet wurde |
Path(__file__).resolve().parent | Skript-Ordner: der Ordner, in dem die .py-Datei liegt |
ordner / "datei.txt" | neuer Pfad (Ordner und Name zusammengesetzt) |
pfad.name / pfad.stem / pfad.suffix | Dateiname / Name ohne Endung / Endung |
pfad.parent | übergeordneter Ordner |
pfad.exists() | True, wenn es die Datei oder den Ordner gibt |
Arbeitsverzeichnis und Skript-Ordner
Python kennt zwei wichtige Ordner. Das Arbeitsverzeichnis ist der Ordner, in dem das Terminal gerade steht, als du python gestartet hast. Der Skript-Ordner ist der Ordner, in dem deine .py-Datei liegt. Beide sind nur dann gleich, wenn du das Skript aus seinem eigenen Ordner startest. Die Ausgabe hängt von deinem Rechner ab:
from pathlib import Path
print(Path.cwd()) # Arbeitsverzeichnis
ORDNER = Path(__file__).resolve().parent # Skript-Ordner
print(ORDNER)
Pfade zusammensetzen
Mit / hängst du Ordner und Dateinamen an. Python setzt automatisch das richtige Trennzeichen: unter Windows \, unter macOS und Linux /. Das Beispiel liegt hier in C:\schule\python:
from pathlib import Path
ORDNER = Path(__file__).resolve().parent
pfad = ORDNER / "daten" / "kunden.csv"
print(pfad)
print(pfad.name)
print(pfad.stem)
print(pfad.suffix)
print(pfad.parent)
print(pfad.exists())
C:\schule\python\daten\kunden.csv kunden.csv kunden .csv C:\schule\python\daten False
Eine Ebene höher: ..
.. bedeutet „eine Ebene höher“. resolve() rechnet einen Pfad mit .. aus. Dasselbe Ziel erreichst du mit .parent:
from pathlib import Path
ORDNER = Path(__file__).resolve().parent
print(ORDNER / ".." / "shared.txt")
print((ORDNER / ".." / "shared.txt").resolve())
print(ORDNER.parent / "shared.txt")
C:\schule\python\..\shared.txt C:\schule\shared.txt C:\schule\shared.txt
ORDNER / "daten" / "noten.txt". Ein Pfad wie "daten/noten.txt" hängt vom Arbeitsverzeichnis ab und findet die Datei nicht mehr, wenn das Programm aus einem anderen Ordner gestartet wird.Aufgabe 1 – Wo bin ich?
Zeit: ca. 8 Minuten
Finde heraus, was Path.cwd() und der Skript-Ordner ORDNER bei dir anzeigen. Lege dafür eine neue Datei block_04_pfade_dateien.py an, die so beginnt:
from pathlib import Path
ORDNER = Path(__file__).resolve().parent
- Gib
Path.cwd()undORDNERaus. - Starte das Skript zweimal im Terminal: einmal aus dem Ordner des Skripts (
python block_04_pfade_dateien.py) und einmal aus dem Ordner darüber (python uebungen/block_04_pfade_dateien.py). Sage vorher voraus: Welcher der beiden Pfade ändert sich, welcher nicht? - Baue mit
/den Pfad zu einer Dateidaten/kunden.csvim Skript-Ordner und gib ihn aus. Gib außerdempfad.name,pfad.suffixundpfad.parentaus. Die Datei muss dafür nicht existieren.
Dateien öffnen und lesen
Die Funktion open(pfad, modus, encoding="utf-8") öffnet eine Datei und liefert ein Dateiobjekt, mit dem du lesen oder schreiben kannst. Zusammen mit with wird die Datei am Ende des eingerückten Blocks automatisch wieder geschlossen (mehr dazu im nächsten Abschnitt). Der Modus legt fest, was du mit der Datei vorhast:
| Modus | Bedeutung | Wenn die Datei fehlt | Wenn die Datei schon da ist |
|---|---|---|---|
"r" | lesen (Standard) | FileNotFoundError | wird gelesen |
"w" | schreiben | wird angelegt | Inhalt wird gelöscht und neu geschrieben |
"a" | anhängen | wird angelegt | Neues kommt ans Ende |
"x" | nur neu anlegen | wird angelegt | FileExistsError |
Mit einem zusätzlichen b (zum Beispiel "rb") liest du Binärdateien wie Bilder. In diesem Block arbeiten wir nur mit Textdateien.
encoding="utf-8" an. Ohne diese Angabe benutzt Windows eine andere Codierung, und aus „Ä“ wird Zeichensalat oder ein UnicodeDecodeError.Die ganze Datei lesen: read()
Für die Beispiele legen wir zuerst eine kleine Datei an (Schreiben kommt gleich noch genauer) und lesen sie dann komplett mit read():
from pathlib import Path
ORDNER = Path(__file__).resolve().parent
pfad = ORDNER / "spruch.txt"
with open(pfad, "w", encoding="utf-8") as datei:
datei.write("Wer A sagt,\nmuss nicht B sagen.\nEr kann auch erkennen,\ndass A falsch war.\n")
with open(pfad, "r", encoding="utf-8") as datei:
inhalt = datei.read()
print(inhalt)
print(len(inhalt), "Zeichen")
Wer A sagt, muss nicht B sagen. Er kann auch erkennen, dass A falsch war. 74 Zeichen
read(10) liest nur die ersten 10 Zeichen.
Zeile für Zeile: readline() und for
readline() liest genau eine Zeile, beim nächsten Aufruf die nächste. Mit for zeile in datei gehst du alle Zeilen der Reihe nach durch:
with open(pfad, "r", encoding="utf-8") as datei:
erste = datei.readline()
zweite = datei.readline()
print(erste.strip())
print(zweite.strip())
with open(pfad, "r", encoding="utf-8") as datei:
nummer = 1
for zeile in datei:
print(nummer, zeile.strip())
nummer += 1
Wer A sagt, muss nicht B sagen. 1 Wer A sagt, 2 muss nicht B sagen. 3 Er kann auch erkennen, 4 dass A falsch war.
read() holt die ganze Datei auf einmal in den Speicher. Große Dateien, zum Beispiel Logdateien mit Millionen Zeilen, liest du besser Zeile für Zeile mit for.Aufgabe 2 – Einkaufszettel
Zeit: ca. 10 Minuten
Ein Einkaufszettel soll als Textdatei gespeichert und wieder eingelesen werden.
- Schreibe mit
with open(..., "w", encoding="utf-8")die Dateieinkauf.txtmit drei Zeilen: Brot, Milch, Äpfel. - Lies die Datei mit
read()und gib den Inhalt aus. - Lies sie erneut und gib sie mit
for zeile in datei: print(zeile)aus. Sage vorher voraus: Warum steht jetzt zwischen den Zeilen eine Leerzeile? Behebe das. - Lass einmal
encoding="utf-8"beim Schreiben weg, aber nicht beim Lesen. Was passiert mit „Äpfel“? Baue es danach wieder ein.
Dateien schließen und with
Eine geöffnete Datei belegt Ressourcen. Unter Windows ist sie oft für andere Programme gesperrt, und Geschriebenes landet erst beim Schließen sicher auf der Festplatte. Ohne with musst du die Datei selbst mit close() schließen:
datei = open(pfad, "r", encoding="utf-8")
print(datei.readline().strip())
datei.close()
print(datei.closed)
Wer A sagt, True
Tritt zwischen open() und close() ein Fehler auf, wird close() nie erreicht. with schließt die Datei dagegen immer, sobald der eingerückte Block endet, auch bei einem Fehler:
with open(pfad, "r", encoding="utf-8") as datei:
print(datei.closed)
print(datei.closed)
False True
with. In älteren Beispielen, auch im Internet, steht oft open() ohne with und ohne encoding. Das funktioniert, ist aber fehleranfälliger.Dateien schreiben und erstellen
write() schreibt Text in die Datei. Einen Zeilenumbruch fügt es nicht automatisch an, dafür schreibst du selbst \n. Zahlen wandelst du vorher in Text um, am einfachsten mit einem f-String. Der Modus entscheidet, ob alter Inhalt erhalten bleibt:
log = ORDNER / "log.txt"
with open(log, "w", encoding="utf-8") as datei:
datei.write("Start\n")
with open(log, "w", encoding="utf-8") as datei:
datei.write("Neustart\n")
with open(log, "a", encoding="utf-8") as datei:
datei.write(f"Punkte: {3 * 7}\n")
with open(log, "r", encoding="utf-8") as datei:
print(datei.read())
Neustart Punkte: 21
„Start“ fehlt: Das zweite "w" hat die Datei geleert und neu geschrieben, erst "a" hat etwas angehängt.
Nur neu anlegen: „x“
Mit "x" legt Python eine Datei nur an, wenn es sie noch nicht gibt. Sonst kommt ein FileExistsError, und nichts wird überschrieben:
try:
with open(log, "x", encoding="utf-8") as datei:
datei.write("Neu\n")
except FileExistsError:
print("log.txt gibt es schon, nichts überschrieben.")
log.txt gibt es schon, nichts überschrieben.
"w" löscht den alten Inhalt ohne Rückfrage. Willst du etwas ergänzen, nimm "a". Darf nie etwas überschrieben werden, nimm "x".Ordner anlegen, Dateien finden und löschen
Auch Ordner verwaltest du mit pathlib. In vielen älteren Beispielen stehen dafür noch Befehle aus dem Modul os, sie machen dasselbe:
| pathlib | älter mit os | Wirkung |
|---|---|---|
pfad.exists() | os.path.exists(pfad) | gibt es die Datei / den Ordner? |
ordner.mkdir(exist_ok=True) | os.mkdir(ordner) | Ordner anlegen |
ordner.glob("*.txt") | os.listdir(ordner) | Inhalt eines Ordners durchgehen |
pfad.unlink() | os.remove(pfad) | Datei löschen |
ordner.rmdir() | os.rmdir(ordner) | leeren Ordner löschen |
Ordner anlegen und Inhalt auflisten
mkdir(exist_ok=True) legt einen Ordner an und meckert nicht, wenn es ihn schon gibt. Mit parents=True werden auch fehlende Ordner darüber angelegt. glob("*.txt") findet alle Dateien mit dieser Endung, stat().st_size liefert die Größe in Bytes:
daten = ORDNER / "daten"
daten.mkdir(exist_ok=True)
for name in ["a.txt", "b.txt", "notiz.md"]:
with open(daten / name, "w", encoding="utf-8") as datei:
datei.write("Hallo\n")
for datei in sorted(daten.glob("*.txt")):
print(datei.name, datei.stat().st_size, "Bytes")
print(daten.is_dir(), (daten / "notiz.md").is_file())
a.txt 7 Bytes b.txt 7 Bytes True True
„Hallo“ und der Zeilenumbruch sind 6 Zeichen. Unter Windows wird \n in der Datei als zwei Zeichen gespeichert, deshalb 7 Bytes.
Dateien und Ordner löschen
unlink() löscht eine Datei, rmdir() einen Ordner, aber nur, wenn er leer ist. Einen vollen Ordner leerst du also zuerst:
ziel = daten / "notiz.md"
if ziel.exists():
ziel.unlink()
print("notiz.md gelöscht")
try:
daten.rmdir()
except OSError:
print("Der Ordner ist nicht leer.")
for datei in daten.glob("*"):
datei.unlink()
daten.rmdir()
print("daten gibt es noch:", daten.exists())
notiz.md gelöscht Der Ordner ist nicht leer. daten gibt es noch: False
exists() und frage bei wichtigen Dateien nach.Übungsaufgaben
Die Aufgaben 3 bis 10 sind die Kernaufgaben, wer schneller ist, macht mit den Bonusaufgaben weiter. Schreibe alle Aufgaben in deine Datei block_04_pfade_dateien.py aus Aufgabe 1. Sie beginnt immer mit diesem Kopf:
from pathlib import Path
ORDNER = Path(__file__).resolve().parent
Alle Dateien, die du erzeugst, landen im Ordner deines Skripts. Schau nach jedem Lauf im Explorer von VS Code nach, was entstanden ist.
Aufgabe 3 – Überschreiben oder anhängen?
Zeit: ca. 8 Minuten
Ein Programm soll mitschreiben, wann es gestartet wurde.
from datetime import datetime
jetzt = datetime.now().strftime("%d.%m.%Y %H:%M:%S")
- Schreibe die Zeile
f"Gestartet: {jetzt}"mit Modus"w"instarts.txt. Starte das Programm dreimal. Wie viele Zeilen stehen in der Datei? - Ändere den Modus auf
"a"und starte wieder dreimal. Und jetzt? - Was passiert mit Modus
"x"beim zweiten Start? Teste es mit einer neuen Dateieinmalig.txtund fange den Fehler ab.
Aufgabe 4 – Die Datei fehlt
Zeit: ca. 8 Minuten
Was passiert, wenn eine Datei nicht da ist? Hier wiederholst du try/except aus Block 3.
- Öffne die Datei
gibtsnicht.txtzum Lesen. Welchen Fehler meldet Python? - Fange den Fehler mit
try/exceptab und gib eine verständliche Meldung mit dem Dateinamen aus. - Löse dasselbe noch einmal ohne
try, indem du vorher mitpfad.exists()prüfst. Welche Lösung findest du besser? Begründe kurz in einem Kommentar.
Aufgabe 5 – Notenliste auswerten
Zeit: ca. 12 Minuten
Eine Lehrkraft hat die Noten einer Probe als Textdatei: pro Zeile Name und Note, getrennt durch ein Semikolon.
noten_text = """Lina;2
Tom;3
Ayşe;1
Ben;4
Mia;2
"""
- Schreibe
noten_textin die Dateinoten.txt. - Lies die Datei Zeile für Zeile, trenne Name und Note mit
split(";")und gib eine Tabelle aus (Name linksbündig, Note rechtsbündig). - Berechne den Durchschnitt und gib ihn mit zwei Nachkommastellen aus.
- Gib aus, wer die beste Note hat.
Zusatz: Füge in noten.txt von Hand eine kaputte Zeile ein (z. B. Max; oder eine Leerzeile). Dein Programm soll sie überspringen und melden, statt abzustürzen.
Aufgabe 6 – Das Gästebuch
Zeit: ca. 10 Minuten
Besucher sollen Einträge hinterlassen können, die auch nach dem Programmende erhalten bleiben.
- Frage in einer Schleife nach Einträgen. Eine leere Eingabe beendet die Eingabe.
- Hänge jeden Eintrag mit Datum an die Datei
gaestebuch.txtan, z. B.07.10.2026 | Schöne Seite! - Gib danach das komplette Gästebuch nummeriert aus:
01: 07.10.2026 | Schöne Seite! - Starte das Programm ein zweites Mal. Bleiben die alten Einträge erhalten? Warum?
Aufgabe 7 – Was geht am Wochenende?
Zeit: ca. 10 Minuten
Eine kleine Suchfunktion für Textdateien, getestet am Anfang von „Max und Moritz“.
gedicht = """Ach was muß man oft von bösen
Kindern hören oder lesen!
Wie zum Beispiel hier von diesen,
Welche Max und Moritz hießen.
Die, anstatt durch weise Lehren
Sich zum Guten zu bekehren,
Oftmals noch darüber lachten
Und sich heimlich lustig machten.
Ja, zur Übeltätigkeit,
Ja, dazu ist man bereit!
Menschen necken, Tiere quälen,
Äpfel, Birnen, Zwetschen stehlen
Das ist freilich angenehmer
Und dazu auch viel bequemer,
Als in Kirche oder Schule
Festzusitzen auf dem Stuhle.
"""
- Speichere das Gedicht in
maxundmoritz.txt. - Frage nach einem Suchwort und gib alle Zeilen aus, in denen es vorkommt, jeweils mit Zeilennummer:
Zeile 11: Menschen necken, Tiere quälen, - Groß- und Kleinschreibung soll egal sein („max“ findet „Max“).
- Wird nichts gefunden, erscheint eine passende Meldung. Sonst steht am Ende z. B. „3 Treffer“.
Aufgabe 8 – Ordnung im Projekt
Zeit: ca. 8 Minuten
Bisher liegen alle Dateien neben dem Skript. Das wird schnell unübersichtlich.
- Lege mit
mkdir(exist_ok=True)einen Unterordnerdatenan. Was bedeutetexist_ok=True? Was passiert ohne? - Schreibe die Datei aus Aufgabe 5 künftig nach
daten/noten.txt. - Gib alle
.txt-Dateien im Skript-Ordner mit Name und Größe in Bytes aus. Tipp:ORDNER.glob("*.txt")undpfad.stat().st_size - Denkfrage: Warum ist
open("daten/noten.txt")gefährlicher alsopen(ORDNER / "daten" / "noten.txt")? Denke an Aufgabe 1.
Aufgabe 9 – Nachbarordner und eine Ebene höher
Zeit: ca. 10 Minuten
In echten Projekten liegen Programm, Daten und Logs in getrennten Ordnern: projekt/shared.txt, projekt/daten/kunden.txt, projekt/logs/ und projekt/src/ für das Programm. Diese Struktur baust du im Skript-Ordner nach.
projekt = ORDNER / "projekt"
src = projekt / "src" # hier läge in echt das Programm main.py
- Lege die Ordner
projekt/daten,projekt/logsundprojekt/srcmitmkdir(parents=True, exist_ok=True)an. Schreibe drei Kunden inprojekt/daten/kunden.txtund zwei Zeilen inprojekt/shared.txt. - Stell dir vor, dein Programm liegt in
src. Baue vonsrcaus mit".."den Pfad zudaten/kunden.txt(ein Nachbarordner) und gib die erste Zeile aus (readline()). - Zähle von
srcaus, wie viele Zeilenshared.txteine Ebene höher hat. Kontrolle: 2. - Gib den Pfad aus Schritt 2 einmal ohne und einmal mit
.resolve()aus. Was ist der Unterschied?
Zusatz: Was bewirkt parents=True? Was passiert ohne, wenn projekt noch nicht existiert?
Aufgabe 10 – Aufräumen mit Rückfrage
Zeit: ca. 8 Minuten
Ein Programm soll einen Ordner samt Inhalt löschen, aber nur nach Rückfrage. Die Vorgabe legt dir dafür einen Testordner mit drei Dateien an.
test = ORDNER / "testordner"
test.mkdir(exist_ok=True)
for nummer in range(1, 4):
with open(test / f"notiz_{nummer}.txt", "w", encoding="utf-8") as datei:
datei.write(f"Notiz {nummer}\n")
- Führe die Vorgabe aus und prüfe im Explorer, dass
testordnermit drei Dateien entstanden ist. - Frage nach: „Soll der Ordner testordner gelöscht werden? (ja/nein)“. Nur bei „ja“ (egal ob groß oder klein geschrieben) wird gelöscht.
- Lösche zuerst alle Dateien im Ordner (
glob("*")undunlink()) und danach den leeren Ordner (rmdir()). Gib aus, wie viele Dateien gelöscht wurden. - Was passiert bei
rmdir(), solange noch Dateien im Ordner sind? Und wenn der Ordner gar nicht existiert? Sorge dafür, dass dein Programm in beiden Fällen nicht abstürzt.
Bonusaufgabe 1 – Das Backup
Wichtige Daten sichert man regelmäßig. Ein Backup-Programm kopiert alle Textdateien aus daten in einen Ordner mit dem heutigen Datum.
- Lege den Ordner
daten/backup_JJJJ-MM-TTmit dem heutigen Datum an (Tipp:datetime.now().strftime("%Y-%m-%d")). - Kopiere jede
.txt-Datei ausdatenin diesen Ordner, indem du sie liest und unter gleichem Namen neu schreibst. - Gib am Ende aus, wie viele Dateien und wie viele Bytes gesichert wurden.
Zusatz: Ein zweiter Lauf am selben Tag würde das Backup überschreiben. Wie verhinderst du das? Baue eine Lösung ein.
Bonusaufgabe 2 – Die Textstatistik
Werte das Gedicht aus Aufgabe 7 aus und speichere einen kleinen Bericht.
- Lies
daten/maxundmoritz.txtund zähle Zeilen, Wörter (split()) und Zeichen ohne Zeilenumbrüche. - Finde die längste Zeile und gib sie mit ihrer Länge aus.
- Schreibe die Ergebnisse als Bericht in
daten/statistik.txtund gib die Datei danach zur Kontrolle aus. Kontrolle: 16 Zeilen.
- Pfade immer vom Skript-Ordner aus bauen:
ORDNER = Path(__file__).resolve().parent, dannORDNER / "daten" / "datei.txt"...geht eine Ebene höher. - Dateien immer mit
with open(pfad, modus, encoding="utf-8") as datei:öffnen, dann werden sie automatisch geschlossen. "r"lesen,"w"überschreiben,"a"anhängen,"x"nur neu anlegen.- Lesen mit
read(),readline()oderfor zeile in datei(Zeilenende mitstrip()entfernen), schreiben mitwrite()und eigenem\n. - Ordner:
mkdir(exist_ok=True),glob(),exists(). Löschen mitunlink()undrmdir()(nur leere Ordner), ohne Papierkorb.
