Python-Kurs / Datei- und Ordnerpfade mit pathlib verwalten

pathlib.Path beschreibt Dateisystempfade und verbindet ihre Bestandteile nach den Regeln des Betriebssystems. Relative Pfade beziehen sich auf das aktuelle Arbeitsverzeichnis; dieses muss nicht der Ordner sein, in dem Ihre Skriptdatei liegt.

Pfade verbinden und den Bezugspunkt festlegen

Path("data") / "expenses.csv" verbindet einen Ordner mit einem Dateinamen, ohne dass Sie Trennzeichen manuell einfügen müssen. Der Operator / ist hier eine Pfadverknüpfung, keine numerische Division. Das Ergebnis ist ein Pfadobjekt. Erst eine Dateisystemoperation wie mkdir oder write_text erstellt tatsächlich einen Ordner oder eine Datei.

Path.cwd() liefert das aktuelle Arbeitsverzeichnis. Wenn eine Datei ausdrücklich neben dem Skript liegen soll, kann in einem normalen Skript Path(__file__).resolve().parent als Basis dienen. In einer interaktiven Sitzung oder einem python -c-Aufruf steht __file__ nicht allgemein zur Verfügung. Entscheiden Sie bewusst, ob Ihre Anwendung relativ zum Startordner, zur Skriptdatei oder zu einem übergebenen Verzeichnis arbeitet.

Ein absoluter rechter Pfadteil kann die bisherige Basis verwerfen. Behandeln Sie base / user_input deshalb nicht automatisch als Zusicherung, dass das Ergebnis innerhalb von base liegt. Die pathlib-Dokumentation beschreibt Pfadoperationen und Dateisystemmethoden.

Eine Übungsdatei erstellen und ihre Eigenschaften ausgeben

Verwenden Sie einen neuen, leeren Übungsordner. Das Beispiel schreibt dort lab-data/expenses.csv und ersetzt den bisherigen Inhalt, wenn diese Datei bereits existiert. Verwenden Sie dafür keine vorhandenen Arbeitsdaten. Speichern Sie den vollständigen Code als paths.py in UTF-8 und starten Sie python paths.py mit dem Projektinterpreter. Unter macOS oder Ubuntu kann außerhalb einer aktivierten Umgebung python3 passen. Zusatzpakete werden nicht benötigt.

from pathlib import Path

base = Path("lab-data")
base.mkdir(exist_ok=True)
path = base / "expenses.csv"
path.write_text("name,amount\nlunch,8000\n", encoding="utf-8")
print(path.name, path.suffix, path.stem)
print(path.is_file(), base.is_dir())
print(sorted(p.name for p in base.glob("*.csv")))

Erwartete Ausgabe im neuen Übungsordner:

expenses.csv .csv expenses
True True
['expenses.csv']

name ist der letzte Pfadbestandteil einschließlich Erweiterung, suffix die letzte Erweiterung mit Punkt und stem der Name ohne diese letzte Erweiterung. Für expenses.csv ergeben sich daher die drei Werte der ersten Zeile. is_file() und is_dir() prüfen die hier angelegte Datei und ihren Ordner.

mkdir(exist_ok=True) erlaubt den bereits vorhandenen passenden Ordner. Es macht aus einer gleichnamigen Datei aber keinen Ordner und legt ohne parents=True auch keine beliebig fehlende Elternstruktur an. write_text schreibt den vollständigen Text mit der angegebenen Kodierung; nach erneutem Start wird kein weiterer Datensatz angehängt.

Suchergebnisse und Existenzprüfungen richtig einordnen

glob("*.csv") betrachtet passende Einträge direkt unter base; rglob("*.csv") sucht auch darunterliegende Verzeichnisse. Ein übereinstimmender Name muss nicht unbedingt eine gewöhnliche Datei sein. Wenn nur Dateien verarbeitet werden sollen, schränken Sie die gefundenen Pfade zusätzlich mit is_file() ein. Verlassen Sie sich für eine stabile Anzeige nicht auf die Suchreihenfolge, sondern sortieren Sie wie im Beispiel.

Die letzte Ausgabe zeigt nur expenses.csv, weil der Übungsordner anfangs leer war. Liegt dort bereits eine andere passende Datei oder ein passend benannter Ordner, kann die Liste weitere Namen enthalten. Das ist kein Rechenfehler des Skripts, sondern eine andere Ausgangslage. Legen Sie getrennte Testdaten an und prüfen Sie die tatsächlichen Treffer, statt die Beispielausgabe für jedes Verzeichnis zu erwarten.

exists() ist keine Reservierung des Pfads. Zwischen einer Prüfung und dem Lesen oder Schreiben kann ein anderer Prozess die Datei ändern. Auch eine positive Existenzprüfung garantiert keine passenden Zugriffsrechte oder einen erfolgreichen Schreibvorgang. Wichtige Dateioperationen benötigen einen ausdrücklich festgelegten Umgang mit Überschreiben, erwarteten Ausnahmen und teilweise abgeschlossenen Arbeiten.

Ausgabeort ändern und erzeugte Daten prüfen

  1. Öffnen Sie die erzeugte Datei mit UTF-8. Sie enthält die Kopfzeile name,amount und die Datenzeile lunch,8000. Die Kommas sind hier die CSV-Trennzeichen; die Dateiendung allein würde noch keinen korrekten Inhalt garantieren.
  2. Ändern Sie nur den Namen expenses.csv zu report.csv. Die Ausgabe der Eigenschaften lautet nun report.csv .csv report. Die ursprüngliche Datei bleibt bestehen, weshalb die sortierte Trefferliste beide Namen zeigen kann. Stellen Sie den Namen danach wieder her.
  3. Öffnen Sie ein Terminal in einem zweiten leeren Übungsordner und starten Sie dieselbe Skriptdatei über ihren vollständigen Pfad. Ein neues lab-data entsteht unter diesem zweiten Arbeitsordner. Die Lage der Skriptdatei allein bestimmt nicht das Ausgabeziel.
  4. Soll das Ziel stattdessen neben der Skriptdatei liegen, ändern Sie die Basis ausdrücklich zu Path(__file__).resolve().parent / "lab-data". Prüfen Sie vor dem Schreiben base.resolve() und vergleichen Sie die Zielorte. Stellen Sie für die ursprüngliche Übung anschließend Path("lab-data") wieder her.

Für eine spätere Bereinigung prüfen Sie den aufgelösten absoluten Pfad und entfernen nur die ausdrücklich für diese Übung angelegten Dateien. Eine Zeichenkettenprüfung wie „beginnt mit dem Ordnernamen“ reicht für fremde Pfade nicht aus: Ähnliche Präfixe, .., absolute Pfade und symbolische Links können die Bedeutung ändern. Eine aufgelöste und nach Pfadbestandteilen geprüfte Zuordnung ist hilfreicher, beseitigt aber nicht jede Änderung zwischen Prüfung und Operation. Die Referenz zu resolve beschreibt die Auflösung; die Anwendung muss zusätzlich ihren erlaubten Bereich und ihre Schreibregeln festlegen.