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:
| Funktion | Liefert 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, stattPermissionErrorzu werfen.Falseheiß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. Nimmisfile()oderPath.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 ausPath(__file__).parent. - Erst prüfen, dann öffnen. Dazwischen kann sich die Datei ändern. Öffne sie in
tryund behandleFileNotFoundError. - Jede Ausnahme fangen.
except Exception:umopen()versteckt auch Tippfehler und Bugs im Code, der die Datei liest. FangFileNotFoundErroroderOSError.
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.