Zum Inhalt springen
aviral gupta

// I4.1 · ca. 30 Min. · Aufbau

Dateien und Ordner mit pathlib

Nach dieser Lektion bauen Sie Pfade mit Path und /, legen Ordner sicher an, lesen und schreiben Textdateien und finden Dateien mit glob-Mustern.

Lektion 1 von 6 in I4 Die Standardbibliothek für echte Programme

Anfang des Moduls

Danach können Sie

  • Pfade mit / bauen und ihre Teile lesen: name, stem, suffix und parent
  • Ordner und Dateien mit mkdir, write_text und read_text anlegen und mit exists prüfen
  • Dateien mit glob-Mustern wie *.txt und **/*.log finden und das Ergebnis sortieren
  1. Aufwärmen · Aufgabe 1 von 7

    Aufwärmen aus Modul I3: Ein Generatorausdruck ist faul. Was gibt das aus?

    squares = (n * n for n in range(4))
    print(sum(squares), sum(squares))
  2. Vorhersagen · Aufgabe 2 von 7

    Sagen Sie es vorher, bevor Sie weiterlesen: Was gibt das aus?

    from pathlib import Path
    
    p = Path("reports") / "2026" / "summary.txt"
    print(p.name, p.stem, p.suffix)
  3. Üben · Aufgabe 3 von 7

    Das Programm läuft womöglich oft. Setzen Sie das Argument ein, damit mkdir nicht scheitert, wenn der Ordner schon existiert.

    folder.mkdir(parents=True, ____=True)
    folder.mkdir(parents=True, =True)
  4. Üben · Aufgabe 4 von 7

    Ein Dateiname mit zwei Punkten. Was gibt das aus?

    from pathlib import Path
    
    p = Path("backup.tar.gz")
    print(p.stem, p.suffix)
  5. Üben · Aufgabe 5 von 7

    Ordnen Sie jedem Aufruf zu, was er zurückgibt.

  6. Denksport · Aufgabe 6 von 7

    Knobelaufgabe. Der Ordner t enthält genau zwei .txt-Dateien. Was gibt das aus?

    from pathlib import Path
    
    folder = Path("t")
    folder.mkdir(exist_ok=True)
    (folder / "a.txt").write_text("a", encoding="utf-8")
    (folder / "b.txt").write_text("b", encoding="utf-8")
    
    texts = folder.glob("*.txt")
    print(len(list(texts)), len(list(texts)))
  7. Anwenden · Aufgabe 7 von 7

    Mini-Aufgabe. Legen Sie einen Ordner notes mit einigen .txt-Dateien und einer .csv-Datei an. Schreiben Sie dann ein Programm, das jede .txt-Datei in notes mit ihrer Zeilenzahl ausgibt, nach Namen sortiert, zum Beispiel a.txt: 3 lines. Die .csv-Datei darf nicht erscheinen.

    Prüfen Sie Ihr Ergebnis anhand dieser Liste

Selbst programmieren

Lesen Sie das ausgearbeitete Beispiel und lösen Sie dann die Übungen. Ihr Code läuft in Ihrem Browser oder auf Ihrem Computer und wird nie hochgeladen.

Ausgearbeitetes Beispiel

Einen Download-Ordner aufräumen

Das Programm legt zuerst einen unordentlichen Ordner downloads mit fünf Dateien an. Dann verschiebt es jede Datei in einen Unterordner, der nach ihrer Endung heißt: pdf, jpg, txt, oder other für eine Datei ohne Endung. Zum Schluss prüft es das Ergebnis mit glob, read_text und exists. Starten Sie es zweimal: Dank exist_ok=True nutzt der zweite Lauf die vorhandenen Ordner.

main.py

from pathlib import Path

# A messy downloads folder to tidy up.
downloads = Path("downloads")
downloads.mkdir(exist_ok=True)
for name in ["report.pdf", "photo.jpg", "notes.txt", "todo.txt", "README"]:
    (downloads / name).write_text(f"contents of {name}\n", encoding="utf-8")

# Move each file into a folder named after its suffix.
for path in sorted(downloads.glob("*")):
    if not path.is_file():
        continue
    kind = path.suffix.removeprefix(".") or "other"
    target = downloads / kind
    target.mkdir(exist_ok=True)
    path.replace(target / path.name)
    print(f"{path.name:<11} -> {kind}/")

print(sorted(p.stem for p in downloads.glob("*/*.txt")))
print((downloads / "txt" / "todo.txt").read_text(encoding="utf-8").strip())
print((downloads / "notes.txt").exists(), (downloads / "txt").is_dir())

Ausführen mit

python main.py

Ausgabe

README      -> other/
notes.txt   -> txt/
photo.jpg   -> jpg/
report.pdf  -> pdf/
todo.txt    -> txt/
['notes', 'todo']
contents of todo.txt
False True
  • README hat keine Endung, path.suffix ist also "", und or wählt "other".
  • sorted() sorgt für eine feste Reihenfolge; glob allein garantiert keine.
  • is_file() überspringt die Unterordner, auf die "*" beim zweiten Lauf ebenfalls passt.
  • replace verschiebt die Datei und überschreibt eine gleichnamige, darum scheitert ein zweiter Lauf nicht.
Ändern und ausführen

Tab rückt ein, Umschalt+Tab rückt aus. Um den Editor mit der Tastatur zu verlassen, drücken Sie Esc und dann Tab.

Beim ersten Ausführen lädt Ihr Browser Python herunter (bis zu 6.5 MB) und speichert es im Cache. Ihr Code bleibt auf Ihrem Gerät.

Übungen

Übung 1 von 2

Dateien nach Endung zählen

Schreiben Sie count_by_suffix(folder). Die Funktion gibt ein dict zurück, das jede Endung auf die Zahl der Dateien direkt in folder mit dieser Endung abbildet. Dateien ohne Endung zählen unter "". Ordner sind keine Dateien: Überspringen Sie sie und schauen Sie nicht hinein. Für a.txt, b.txt, c.csv, README und einen Unterordner ist das Ergebnis {".txt": 2, ".csv": 1, "": 1}.

Tab rückt ein, Umschalt+Tab rückt aus. Um den Editor mit der Tastatur zu verlassen, drücken Sie Esc und dann Tab.

Beim ersten Ausführen lädt Ihr Browser Python herunter (bis zu 6.5 MB) und speichert es im Cache. Ihr Code bleibt auf Ihrem Gerät.

Hinweise
  1. Hinweis 1

    folder.glob("*") liefert alles direkt in folder, Dateien und Unterordner.

  2. Hinweis 2

    path.is_file() ist für einen Ordner False, ein if überspringt also Unterordner.

  3. Hinweis 3

    counts[path.suffix] = counts.get(path.suffix, 0) + 1 zählt jede Endung; eine Datei ohne Endung hat suffix "".

Eine Lösung zeigen

Ein möglicher Lösungsweg. Ihrer kann anders aussehen und trotzdem alle Prüfungen bestehen.

from pathlib import Path


def count_by_suffix(folder: Path) -> dict[str, int]:
    counts: dict[str, int] = {}
    for path in folder.glob("*"):
        if path.is_file():
            counts[path.suffix] = counts.get(path.suffix, 0) + 1
    return counts


if __name__ == "__main__":
    print(count_by_suffix(Path(".")))
Auf dem eigenen Computer ausführen

Installieren Sie Python 3.14 oder neuer. Speichern Sie diese Dateien in einem Ordner, öffnen Sie dort ein Terminal und führen Sie die Befehle unten aus.

main.py

from pathlib import Path


def count_by_suffix(folder: Path) -> dict[str, int]:
    counts: dict[str, int] = {}
    # Look at every file in folder and count its suffix.
    return counts


if __name__ == "__main__":
    print(count_by_suffix(Path(".")))

test_main.py

from pathlib import Path

from main import count_by_suffix


def make(folder, names):
    root = Path(folder)
    root.mkdir(exist_ok=True)
    for name in names:
        (root / name).write_text("x", encoding="utf-8")
    return root


def test_counts():
    """Zwei .txt-Dateien, eine .csv und eine Datei ohne Endung"""
    root = make("t_counts", ["a.txt", "b.txt", "c.csv", "README"])
    got = count_by_suffix(root)
    assert got == {".txt": 2, ".csv": 1, "": 1}, f"count_by_suffix gab {got!r} zurück"


def test_skips_folders():
    """Unterordner und die Dateien darin werden nicht gezählt"""
    root = make("t_folders", ["a.txt"])
    (root / "sub").mkdir(exist_ok=True)
    (root / "sub" / "b.txt").write_text("x", encoding="utf-8")
    got = count_by_suffix(root)
    assert got == {".txt": 1}, f"mit a.txt und sub/b.txt gab count_by_suffix {got!r} zurück, erwartet {{'.txt': 1}}"


def test_empty():
    """Ein leerer Ordner ergibt ein leeres dict"""
    root = make("t_empty", [])
    got = count_by_suffix(root)
    assert got == {}, f"für einen leeren Ordner gab count_by_suffix {got!r} zurück"

Unter macOS und Linux tippen Sie python3, wo in diesen Befehlen python steht, wie in der ersten Lektion.

Programm ausführen:

python main.py

Prüfungen ausführen (learnrun.py muss im selben Ordner liegen):

python learnrun.py test
learnrun.py herunterladen

Übung 2 von 2

Ein Berichtsarchiv

Schreiben Sie save_report(base, year, title, text). Die Funktion speichert text in base/<year>/<title>.md, legt dabei fehlende Ordner an und gibt den Pfad der Datei zurück. Erneutes Speichern muss funktionieren. Schreiben Sie dann report_titles(base, year): Sie gibt die sortierten Titel (Namen ohne .md) der .md-Dateien im Ordner dieses Jahres zurück, und [], wenn der Ordner nicht existiert.

Tab rückt ein, Umschalt+Tab rückt aus. Um den Editor mit der Tastatur zu verlassen, drücken Sie Esc und dann Tab.

Beim ersten Ausführen lädt Ihr Browser Python herunter (bis zu 6.5 MB) und speichert es im Cache. Ihr Code bleibt auf Ihrem Gerät.

Hinweise
  1. Hinweis 1

    Bauen Sie zuerst den Ordnerpfad: folder = base / str(year). Rufen Sie dann folder.mkdir(parents=True, exist_ok=True) auf.

  2. Hinweis 2

    Die Datei ist folder / (title + ".md"); write_text legt sie an oder ersetzt sie.

  3. Hinweis 3

    Prüfen Sie in report_titles zuerst folder.exists(), dann sortieren Sie path.stem für jeden path in folder.glob("*.md").

Eine Lösung zeigen

Ein möglicher Lösungsweg. Ihrer kann anders aussehen und trotzdem alle Prüfungen bestehen.

from pathlib import Path


def save_report(base: Path, year: int, title: str, text: str) -> Path:
    folder = base / str(year)
    folder.mkdir(parents=True, exist_ok=True)
    path = folder / (title + ".md")
    path.write_text(text, encoding="utf-8")
    return path


def report_titles(base: Path, year: int) -> list[str]:
    folder = base / str(year)
    if not folder.exists():
        return []
    return sorted(path.stem for path in folder.glob("*.md"))


if __name__ == "__main__":
    save_report(Path("reports"), 2026, "september", "All good.")
    print(report_titles(Path("reports"), 2026))
Auf dem eigenen Computer ausführen

Installieren Sie Python 3.14 oder neuer. Speichern Sie diese Dateien in einem Ordner, öffnen Sie dort ein Terminal und führen Sie die Befehle unten aus.

main.py

from pathlib import Path


def save_report(base: Path, year: int, title: str, text: str) -> Path:
    path = base / str(year) / (title + ".md")
    path.write_text(text, encoding="utf-8")
    return path


def report_titles(base: Path, year: int) -> list[str]:
    return []


if __name__ == "__main__":
    save_report(Path("reports"), 2026, "september", "All good.")
    print(report_titles(Path("reports"), 2026))

test_main.py

from pathlib import Path

from main import report_titles, save_report


def test_saves_file():
    """save_report legt die Ordner an und schreibt den Text"""
    path = save_report(Path("t_save") / "reports", 2026, "may", "Sales up.")
    assert path == Path("t_save/reports/2026/may.md"), f"save_report gab {path!r} zurück"
    text = path.read_text(encoding="utf-8")
    assert text == "Sales up.", f"die Datei enthält {text!r}, erwartet 'Sales up.'"


def test_save_twice():
    """Ein zweiter Bericht im selben Jahr lässt sich speichern"""
    base = Path("t_twice")
    save_report(base, 2025, "one", "1")
    save_report(base, 2025, "two", "2")
    got = (base / "2025" / "two.md").read_text(encoding="utf-8")
    assert got == "2", f"der zweite Bericht enthält {got!r}, erwartet '2'"


def test_titles_sorted():
    """report_titles listet nur .md-Dateien, sortiert und ohne .md"""
    base = Path("t_titles")
    for title in ["march", "april", "june"]:
        save_report(base, 2024, title, "x")
    (base / "2024" / "notes.txt").write_text("x", encoding="utf-8")
    got = report_titles(base, 2024)
    assert got == ["april", "june", "march"], f"report_titles gab {got!r} zurück"


def test_missing_year():
    """Ein Jahr ohne Ordner ergibt []"""
    got = report_titles(Path("t_missing"), 1999)
    assert got == [], f"für einen fehlenden Ordner gab report_titles {got!r} zurück"

Unter macOS und Linux tippen Sie python3, wo in diesen Befehlen python steht, wie in der ersten Lektion.

Programm ausführen:

python main.py

Prüfungen ausführen (learnrun.py muss im selben Ordner liegen):

python learnrun.py test
learnrun.py herunterladen

Häufige Fehler

Path und String mit + verbinden

from pathlib import Path

folder = Path("data")
print(folder + "/scores.txt")

Was Python ausgibt

TypeError: unsupported operand type(s) for +: 'PosixPath' and 'str'

Warum, und die Lösung

Ein Path ist kein String, darum funktioniert + nicht. Verbinden Sie mit /: folder / "scores.txt". Unter Windows nennt die Meldung WindowsPath statt PosixPath. Brauchen Sie den Pfad als Text, etwa für eine Meldung, nehmen Sie str(folder / "scores.txt").

Einen Ordner anlegen, der schon existiert

from pathlib import Path

Path("out").mkdir()
Path("out").mkdir()

Was Python ausgibt

File exists: 'out'

Warum, und die Lösung

Die ganze Zeile lautet FileExistsError: [Errno 17] File exists: 'out' (der Browser zeigt eine andere Nummer). mkdir scheitert, wenn der Ordner schon da ist. Ein Programm, das beim ersten Mal läuft, bricht also beim zweiten Mal ab. Übergeben Sie exist_ok=True, wenn ein vorhandener Ordner in Ordnung ist.

Verschachtelte Ordner in einem Schritt anlegen

from pathlib import Path

Path("backup/2026/09").mkdir()

Was Python ausgibt

No such file or directory: 'backup/2026/09'

Warum, und die Lösung

Die ganze Zeile lautet FileNotFoundError: [Errno 2] No such file or directory: 'backup/2026/09'. mkdir legt nur den letzten Ordner an, und backup/2026 gibt es noch nicht. Übergeben Sie parents=True, damit die fehlenden Ordner darüber entstehen, meist zusammen mit exist_ok=True.

Python im Browser: Pyodide 314.0.7, MPL-2.0. Lizenz und Quellcode

Abschlussquiz

5 Fragen, ohne Hinweise. Ab 80 % ist die Lektion abgeschlossen.

Erledigen Sie zuerst alle Aufgaben oben, um das Abschlussquiz freizuschalten.

Problem melden

Etwas ist falsch oder unklar? Beschreiben Sie es kurz, dann wird es geprüft und korrigiert.

#

Mindestens 20 Zeichen.

Nur, wenn Sie eine Antwort wünschen.

Kernideen

Ein Pfad ist ein Objekt, verbunden mit /

Path("data") / "raw" / "sales.csv" baut einen Pfad aus Teilen, wie der Schrägstrich auf der Kommandozeile, ohne Strings zusammenzukleben. Das Objekt kennt seine Teile: name ist "sales.csv", stem ist "sales", suffix ist ".csv", und parent ist der Ordner darüber. Bei "archive.tar.gz" ist suffix nur der letzte Teil, ".gz". print zeigt hier und im Browser data/raw/sales.csv; unter Windows erscheinen Backslashes, und derselbe Code läuft auf beiden. Einen str und einen Path kann man nicht mit + verbinden.

Ordner und Dateien

mkdir legt einen Ordner an. Es scheitert mit FileExistsError, wenn der Ordner schon da ist, außer Sie übergeben exist_ok=True, und mit FileNotFoundError, wenn ein übergeordneter Ordner fehlt, außer Sie übergeben parents=True. write_text(text, encoding="utf-8") ersetzt die ganze Datei und gibt die Zahl der geschriebenen Zeichen zurück; read_text(encoding="utf-8") liefert die ganze Datei als einen String. Beide öffnen und schließen die Datei selbst. exists, is_file und is_dir fragen nur ab und ändern nichts.

Dateien mit glob finden

folder.glob("*.txt") liefert die Pfade in folder, die zum Muster passen. * passt auf einen beliebigen Teil eines Namens, ? auf ein Zeichen und ** auf beliebig viele Ordnerebenen. "**/*.log" findet also .log-Dateien in jeder Tiefe, den Ordner selbst eingeschlossen. Die Pfade kommen in keiner bestimmten Reihenfolge; sortieren Sie, wenn es darauf ankommt. glob liefert einen Iterator, der nur einmal durchlaufen werden kann. Speichern Sie list(folder.glob(...)), wenn Sie die Pfade zweimal brauchen. "*" passt auch auf Ordner; is_file() filtert sie heraus.

Quellen

Zuletzt geprüft am 29. September 2026