Menu

Python: Prüfen, ob eine Datei existiert (os.path, pathlib, try/except)

Drei Wege, in Python zu prüfen, ob eine Datei existiert: os.path.exists und isfile, Path.exists und is_file aus pathlib und das Öffnen der Datei in try/except FileNotFoundError.

Diese Seite enthält ausführbare Editoren - bearbeiten, ausführen und Ausgabe sofort sehen.

Die kurze Antwort

Um zu prüfen, ob eine Datei existiert, nimm os.path.isfile() aus der Standardbibliothek. Die Funktion liefert True, wenn der Pfad eine vorhandene reguläre Datei bezeichnet, und sonst False. Bei einem fehlenden Pfad wirft sie nie einen Fehler.

Pfade sind relativ zu dem Ordner, in dem das Programm läuft (dem aktuellen Arbeitsverzeichnis), es sei denn, du übergibst einen absoluten Pfad wie /home/ada/notes.txt oder C:\Users\Ada\notes.txt.

Der Rest dieser Seite zeigt die anderen Wege, dieselbe Frage zu stellen, wie sie sich unterscheiden und in welchem Fall du sie gar nicht stellen solltest.

os.path.exists vs. isfile vs. isdir

Das Modul os.path hat drei verwandte Prüfungen, und sie beantworten leicht unterschiedliche Fragen:

FunktionLiefert True, wenn der Pfad Folgendes ist
os.path.exists(p)irgendetwas Vorhandenes: eine Datei, ein Verzeichnis oder ein funktionierender Symlink
os.path.isfile(p)eine vorhandene reguläre Datei
os.path.isdir(p)ein vorhandenes Verzeichnis

Der Unterschied zeigt sich, sobald ein Verzeichnis im Spiel ist:

Ausgabe:

reports True False True
reports/summary.txt True True False
reports/old.txt False False False

os.path.exists("reports") ist True, obwohl reports ein Ordner ist. Wenn dein Code den Pfad gleich als Datei lesen will, ist exists die falsche Prüfung: Ein Verzeichnis würde sie bestehen, und open("reports") würde danach scheitern (mit IsADirectoryError unter Linux und macOS, mit PermissionError unter Windows). Nimm isfile, wenn du eine Datei meinst, und isdir, wenn du einen Ordner meinst.

Zwei weitere Details zu diesen drei os.path-Funktionen:

  • Einem Symlink wird gefolgt. Ein Link auf eine echte Datei zählt als Datei; ein kaputter Link (sein Ziel ist weg) liefert bei allen dreien False.
  • Wenn Python nicht in einen Ordner hineinschauen darf, liefert die Prüfung False, statt PermissionError zu werfen. False heißt also „nicht gefunden oder nicht erreichbar“, nicht streng „existiert nicht“.

Prüfen mit pathlib

pathlib ist die objektorientierte Pfad-API der Standardbibliothek, und der meiste neue Code nutzt sie. Ein Path-Objekt hat dieselben drei Prüfungen als Methoden:

Path.exists(), Path.is_file() und Path.is_dir() verhalten sich wie os.path.exists, isfile und isdir. Der Operator / verbindet Pfadteile mit dem richtigen Trennzeichen für das Betriebssystem, deshalb funktioniert folder / "summary.txt" unter Windows, macOS und Linux gleichermaßen. Wie du über Path-Objekte liest und schreibst, steht unter Dateiverarbeitung.

Welche Variante solltest du nehmen? Wenn der Rest deines Codes ohnehin Path-Objekte herumreicht, bleib bei pathlib. Wenn du mit einfachen Strings und os-Funktionen arbeitest, ist os.path.isfile genauso korrekt. Beide liefern dieselben Antworten.

Warum vorheriges Prüfen der falsche Schritt sein kann

Der häufigste Grund, auf eine vorhandene Datei zu prüfen, ist, sie danach zu öffnen:

import os

if os.path.isfile("config.txt"):
    with open("config.txt") as f:      # the file might be gone by now
        settings = f.read()
else:
    settings = ""

Das hat eine Lücke. Zwischen dem Aufruf von isfile() und dem Aufruf von open() kann ein anderes Programm, ein anderer Thread oder der Benutzer die Datei löschen oder umbenennen. Die Prüfung sagte True, das Öffnen scheitert trotzdem, und dein Programm stürzt doch mit FileNotFoundError ab. Diese Lücke heißt Race Condition oder „time of check to time of use“. Auf deinem eigenen Laptop ist sie selten, auf einem ausgelasteten Server, auf dem sich mehrere Prozesse einen Ordner teilen, deutlich weniger selten.

Die Lösung: Lass die separate Prüfung weg und mach open() selbst zur Prüfung. Python wirft FileNotFoundError, wenn die Datei fehlt, und das behandelst du in except:

Ausgabe:

theme=dark
(no settings file, using defaults)

Jetzt gibt es eine Operation statt zwei, also nichts mehr, wogegen ein Wettlauf entstehen könnte. Dieser Stil hat in der Python-Community einen Namen: EAFP, „easier to ask forgiveness than permission“ (lieber um Verzeihung bitten als um Erlaubnis). Der Gegenstil, erst zu prüfen, heißt LBYL, „look before you leap“ (erst schauen, dann springen). Bei Dateien neigt Python zu EAFP, weil nur das Betriebssystem die Antwort in dem Moment kennt, in dem du die Datei öffnest.

FileNotFoundError ist nicht das Einzige, was schiefgehen kann. Ein Pfad, der ein Verzeichnis ist, wirft IsADirectoryError (PermissionError unter Windows), und eine Datei, die du nicht lesen darfst, wirft PermissionError. Alle drei sind Unterklassen von OSError, also fängt except OSError: jeden Fall von „konnte nicht geöffnet werden“ auf einmal. Die Seite zu Ausnahmen zeigt, wie du zwischen dem Fangen eines bestimmten Fehlers und dem Fangen einer ganzen Familie wählst.

Wann eine einfache Prüfung in Ordnung ist

Erst zu prüfen ist nicht in jedem Fall falsch. Es ist das richtige Werkzeug, wenn du nur die Antwort brauchst und nicht in der nächsten Zeile etwas mit der Datei machst:

  • entscheiden, welche Meldung du anzeigst („3 gespeicherte Spiele gefunden“)
  • einen vom Benutzer eingetippten Pfad prüfen, bevor ein langer Job startet
  • Arbeit überspringen, die schon erledigt ist, wenn eine veraltete Antwort nur eine Wiederholung kostet

Die Faustregel: Wenn du die Datei öffnen, lesen, schreiben oder löschen willst, tu das in try. Wenn du es nur wissen willst, reicht isfile() oder Path.is_file().

Eine Datei nur anlegen, wenn sie noch nicht existiert

Auch die umgekehrte Frage kommt vor: „Schreib diese Datei, aber überschreib nie eine vorhandene.“ Die naheliegende Version hat dieselbe Race Condition wie vorher:

if not os.path.exists("report.txt"):
    with open("report.txt", "w") as f:   # another process may create it first
        f.write("new report\n")

Der Modus "x" (exklusives Anlegen) erledigt beide Schritte in einem. Er legt die Datei an oder wirft FileExistsError, wenn der Name schon vergeben ist:

Ausgabe:

attempt 1: created report.txt
attempt 2: report.txt already exists, left it alone

Für Ordner legen os.makedirs(path, exist_ok=True) und Path(path).mkdir(parents=True, exist_ok=True) das Verzeichnis samt fehlender übergeordneter Verzeichnisse an und tun nichts, wenn es schon da ist. Vorher isdir() aufzurufen ist unnötig.

Häufige Fehler

  • exists() verwenden, wenn du eine Datei meinst. Ein gleichnamiges Verzeichnis besteht die Prüfung. Nimm isfile() oder Path.is_file().
  • Vergessen, wo relative Pfade beginnen. "data.txt" wird im aktuellen Arbeitsverzeichnis gesucht, also dort, wo du das Programm gestartet hast, nicht unbedingt im Ordner mit dem Skript. Um eine Datei neben dem Skript zu finden, bau den Pfad aus Path(__file__).parent.
  • Erst prüfen, dann öffnen. Dazwischen kann sich die Datei ändern. Öffne sie in try und behandle FileNotFoundError.
  • Jede Ausnahme fangen. except Exception: um open() versteckt auch Tippfehler und Bugs im Code, der die Datei liest. Fang FileNotFoundError oder OSError.

Häufig gestellte Fragen

Wie prüfe ich in Python, ob eine Datei existiert?

Importiere os und ruf os.path.isfile("data.txt") auf. Das liefert nur für eine vorhandene reguläre Datei True. Mit pathlib heißt es Path("data.txt").is_file(). Nimm os.path.exists() oder Path.exists(), wenn auch ein Verzeichnis mit diesem Namen zählen soll.

Was ist der Unterschied zwischen os.path.exists und os.path.isfile?

os.path.exists(p) ist für alles unter diesem Pfad True: eine Datei, ein Verzeichnis oder einen Symlink, der auf etwas Vorhandenes zeigt. os.path.isfile(p) ist nur für eine reguläre Datei True und liefert für ein Verzeichnis also False. os.path.isdir(p) ist das Gegenstück für Verzeichnisse.

Sollte ich prüfen, ob eine Datei existiert, bevor ich sie öffne?

Meistens nicht. Zwischen der Prüfung und dem Aufruf von open() kann die Datei gelöscht oder angelegt werden, die Prüfung garantiert also nichts. Öffne die Datei direkt in try und behandle FileNotFoundError in except. Eine eigene Existenzprüfung passt, wenn du nur die Antwort brauchst, zum Beispiel um zu entscheiden, welche Meldung du anzeigst.

Wie lege ich eine Datei nur an, wenn sie noch nicht existiert?

Öffne sie im Modus "x": open("report.txt", "x"). Python legt die Datei an oder wirft FileExistsError, wenn dort schon etwas liegt. Prüfung und Anlegen passieren in einem Schritt, also kann sich kein anderes Programm dazwischenschieben.

Coddy programming languages illustration

Lerne mit Coddy zu programmieren

LOS GEHT'S