5668 Stimmen

Wie kann ich ein verschachteltes Verzeichnis sicher erstellen?

Wie kann man am elegantesten prüfen, ob das Verzeichnis, in das eine Datei geschrieben werden soll, existiert, und wenn nicht, das Verzeichnis mit Python erstellen? Das habe ich versucht:

import os

file_path = "/my/directory/filename.txt"
directory = os.path.dirname(file_path)

try:
    os.stat(directory)
except:
    os.mkdir(directory)

f = file(filename)

Irgendwie habe ich die os.path.exists (Danke Kanja, Blair und Douglas). Dies ist, was ich jetzt habe:

def ensure_dir(file_path):
    directory = os.path.dirname(file_path)
    if not os.path.exists(directory):
        os.makedirs(directory)

Gibt es ein Kennzeichen für open() die dafür sorgt, dass dies automatisch geschieht?

42 Stimmen

Im Allgemeinen müssen Sie den Fall berücksichtigen, dass im Dateinamen kein Verzeichnis enthalten ist. Auf meinem Rechner ergibt dirname('foo.txt') '', das nicht existiert und makedirs() zum Scheitern bringt.

9 Stimmen

Wenn der Pfad existiert, muss man nicht nur prüfen, ob es sich um ein Verzeichnis und nicht um eine normale Datei oder ein anderes Objekt handelt (viele Antworten prüfen dies), sondern auch, ob es beschreibbar ist (ich habe keine Antwort gefunden, die dies geprüft hat)

14 Stimmen

Falls Sie hierher gekommen sind, um übergeordnete Verzeichnisse einer Dateipfadzeichenkette zu erstellen p Hier ist mein Codeschnipsel: os.makedirs(p[:p.rindex(os.path.sep)], exist_ok=True)

7097voto

Blair Conrad Punkte 217777

Unter Python 3.5 verwenden Sie pathlib.Path.mkdir :

from pathlib import Path
Path("/my/directory").mkdir(parents=True, exist_ok=True)

Für ältere Versionen von Python sehe ich zwei Antworten mit guten Eigenschaften, jede mit einem kleinen Makel, also werde ich meine Meinung dazu sagen:

トライ os.path.exists und berücksichtigen os.makedirs für die Schöpfung.

import os
if not os.path.exists(directory):
    os.makedirs(directory)

Wie in den Kommentaren und anderswo erwähnt, gibt es eine Wettlaufbedingung - wenn das Verzeichnis zwischen dem os.path.exists et le os.makedirs Anrufe, die os.makedirs scheitert mit einer OSError . Leider ist das Auffangen von Gummitüchern OSError und die Fortsetzung ist nicht narrensicher, da ein Fehler bei der Erstellung des Verzeichnisses aufgrund anderer Faktoren, wie unzureichende Berechtigungen, volle Festplatte usw., ignoriert wird.

Eine Möglichkeit wäre, die OSError und untersuchen Sie den eingebetteten Fehlercode (siehe Gibt es eine plattformübergreifende Möglichkeit, Informationen von Pythons OSError zu erhalten ):

import os, errno

try:
    os.makedirs(directory)
except OSError as e:
    if e.errno != errno.EEXIST:
        raise

Alternativ dazu könnte es eine zweite os.path.exists Aber nehmen wir an, dass ein anderer das Verzeichnis nach der ersten Prüfung erstellt und vor der zweiten Prüfung wieder entfernt hat - wir könnten immer noch getäuscht werden.

Je nach Anwendung kann die Gefahr gleichzeitiger Operationen größer oder kleiner sein als die Gefahr, die von anderen Faktoren, wie z. B. den Dateiberechtigungen, ausgeht. Der Entwickler müsste mehr über die zu entwickelnde Anwendung und ihre erwartete Umgebung wissen, bevor er sich für eine Implementierung entscheidet.

Moderne Versionen von Python verbessern diesen Code erheblich, sowohl durch die Offenlegung von FileExistsError (in 3.3+)...

try:
    os.makedirs("path/to/directory")
except FileExistsError:
    # directory already exists
    pass

...und durch die Erlaubnis ein Schlüsselwortargument für os.makedirs genannt. exist_ok (in 3.2+).

os.makedirs("path/to/directory", exist_ok=True)  # succeeds even if directory exists.

12 Stimmen

Die Wettlaufbedingung ist ein guter Punkt, aber der Ansatz in stackoverflow.com/questions/273192/#273208 wird ein Fehler bei der Erstellung des Verzeichnisses maskiert. Fühlen Sie sich nicht schlecht, wenn Sie mit "Nein" stimmen, weil Ihnen die Antwort nicht gefällt. Dafür sind Abstimmungen ja da.

38 Stimmen

Denken Sie daran, dass os.path.exists() nicht frei ist. Wenn das Verzeichnis im Normalfall vorhanden ist, dann sollte der Fall, dass es nicht vorhanden ist, als Ausnahme behandelt werden. Mit anderen Worten: Versuchen Sie, Ihre Datei zu öffnen und in sie zu schreiben, fangen Sie die OSError-Ausnahme ab und führen Sie auf der Grundlage von errno Ihr makedir() aus und versuchen Sie es erneut oder rufen Sie es erneut auf. Dies führt zu einer Verdoppelung des Codes, es sei denn, Sie verpacken das Schreiben in eine lokale Methode.

27 Stimmen

os.path.exists gibt auch zurück True für eine Datei. Ich habe eine Antwort geschrieben, um dieses Problem zu lösen.

1546voto

Asclepius Punkte 48774

Python 3.5+:

import pathlib
pathlib.Path('/my/directory').mkdir(parents=True, exist_ok=True) 

pathlib.Path.mkdir wie oben verwendet, erstellt das Verzeichnis rekursiv und löst keine Ausnahme aus, wenn das Verzeichnis bereits existiert. Wenn Sie nicht wollen oder brauchen, dass die Eltern erstellt werden, überspringen Sie die parents Argument.

Python 3.2+:

Verwendung von pathlib :

Wenn Sie können, installieren Sie die aktuelle pathlib Rückport genannt pathlib2 . Installieren Sie nicht den älteren, nicht gewarteten Backport namens pathlib . Lesen Sie dann den Abschnitt über Python 3.5+ und verwenden Sie ihn genauso.

Wenn Sie Python 3.4 verwenden, auch wenn es mit pathlib Es fehlt das nützliche exist_ok Option. Der Backport soll eine neuere und bessere Implementierung von mkdir die diese fehlende Option enthält.

Verwendung von os :

import os
os.makedirs(path, exist_ok=True)

os.makedirs wie oben verwendet, erstellt das Verzeichnis rekursiv und löst keine Ausnahme aus, wenn das Verzeichnis bereits existiert. Es hat die optionale exist_ok nur bei Verwendung von Python 3.2+, mit einem Standardwert von False . Dieses Argument gibt es in Python 2.x bis 2.7 nicht. Daher besteht keine Notwendigkeit für eine manuelle Ausnahmebehandlung wie bei Python 2.7.

Python 2.7+:

Verwendung von pathlib :

Wenn Sie können, installieren Sie die aktuelle pathlib Rückport genannt pathlib2 . Installieren Sie nicht den älteren, nicht gewarteten Backport namens pathlib . Lesen Sie dann den Abschnitt über Python 3.5+ und verwenden Sie ihn genauso.

Verwendung von os :

import os
try: 
    os.makedirs(path)
except OSError:
    if not os.path.isdir(path):
        raise

Während eine naive Lösung zunächst die os.path.isdir gefolgt von os.makedirs Bei der obigen Lösung wird die Reihenfolge der beiden Operationen umgekehrt. Auf diese Weise wird eine häufige Wettlaufsituation verhindert, die mit einem doppelten Versuch, das Verzeichnis zu erstellen, zu tun hat, und außerdem werden Dateien von Verzeichnissen unterschieden.

Beachten Sie, dass das Erfassen der Ausnahme und die Verwendung von errno ist von begrenztem Nutzen, weil OSError: [Errno 17] File exists d.h. errno.EEXIST wird sowohl für Dateien als auch für Verzeichnisse ausgelöst. Es ist zuverlässiger, einfach zu prüfen, ob das Verzeichnis existiert.

Alternativ:

mkpath erstellt das verschachtelte Verzeichnis und tut nichts, wenn das Verzeichnis bereits existiert. Dies funktioniert sowohl in Python 2 als auch in 3.

import distutils.dir_util
distutils.dir_util.mkpath(path)

Per Fehler 10948 Eine schwerwiegende Einschränkung dieser Alternative ist, dass sie nur einmal pro Python-Prozess für einen bestimmten Pfad funktioniert. Mit anderen Worten, wenn Sie damit ein Verzeichnis erstellen, dann das Verzeichnis von innerhalb oder außerhalb von Python löschen und dann mkpath erneut, um dasselbe Verzeichnis wiederherzustellen, mkpath wird einfach stillschweigend seine ungültige, zwischengespeicherte Information verwenden, dass das Verzeichnis zuvor erstellt wurde, und wird das Verzeichnis nicht tatsächlich erneut erstellen. Im Gegensatz dazu, os.makedirs stützt sich nicht auf einen solchen Cache. Diese Einschränkung kann für einige Anwendungen in Ordnung sein.


In Bezug auf das Verzeichnis der Modus Wenn Sie sich dafür interessieren, lesen Sie bitte in der Dokumentation nach.

17 Stimmen

Diese Antwort deckt so ziemlich jeden Sonderfall ab, soweit ich das beurteilen kann. Ich plane, dies in ein "if not os.path.isdir()" zu verpacken, da ich erwarte, dass das Verzeichnis fast immer existiert und ich die Ausnahme auf diese Weise vermeiden kann.

7 Stimmen

@CharlesL. Eine Ausnahme ist wahrscheinlich billiger als das Festplatten-IO der Prüfung, wenn Ihr Grund die Leistung ist.

2 Stimmen

@jpmc26 aber makedirs macht zusätzlich stat, umask, lstat, wenn es nur prüft, um OSError zu werfen.

658voto

Heikki Toivonen Punkte 30634

Die Verwendung von try except und dem richtigen Fehlercode aus dem errno-Modul beseitigt die Race Condition und ist plattformübergreifend:

import os
import errno

def make_sure_path_exists(path):
    try:
        os.makedirs(path)
    except OSError as exception:
        if exception.errno != errno.EEXIST:
            raise

Mit anderen Worten: Wir versuchen, die Verzeichnisse zu erstellen, aber wenn sie bereits existieren, ignorieren wir den Fehler. Andererseits wird jeder andere Fehler gemeldet. Wenn Sie zum Beispiel das Verzeichnis 'a' vorher erstellen und ihm alle Rechte entziehen, erhalten Sie eine OSError erhoben mit errno.EACCES (Erlaubnis verweigert, Fehler 13).

2 Stimmen

Was ist der allgemeine Grund gegen Warum ziehen die Leute die if-Anweisung der try/except-Anweisung vor? Ist try/except gefährlicher, wenn man den Fehler übersieht?

26 Stimmen

Die akzeptierte Antwort ist in der Tat gefährlich, weil sie eine Rassenbedingung enthält. Sie ist jedoch einfacher. Wenn Sie sich der Rassenbedingung nicht bewusst sind oder glauben, dass sie nicht auf Sie zutrifft, wäre dies Ihre erste Wahl.

18 Stimmen

Die Ausnahme wird nur ausgelöst, wenn exception.errno != errno.EEXIST ignoriert unbeabsichtigt den Fall, dass der Pfad zwar existiert, aber ein Nicht-Verzeichnis-Objekt wie z.B. eine Datei ist. Die Ausnahme sollte idealerweise ausgelöst werden, wenn der Pfad ein Nicht-Verzeichnis-Objekt ist.

142voto

hiro protagonist Punkte 39728

Beginnend mit Python 3.5, pathlib.Path.mkdir hat eine exist_ok Flagge:

from pathlib import Path
path = Path('/my/directory/filename.txt')
path.parent.mkdir(parents=True, exist_ok=True) 
# path.parent ~ os.path.dirname(path)

Dadurch wird das Verzeichnis rekursiv erstellt und es wird keine Ausnahme ausgelöst, wenn das Verzeichnis bereits existiert.

(ebenso wie os.makedirs bekam eine exist_ok Flagge ab Python 3.2 z.B. os.makedirs(path, exist_ok=True) )


Hinweis: Als ich diese Antwort veröffentlichte, wurde in keiner der anderen Antworten erwähnt, dass exist_ok ...

130voto

Ich persönlich würde empfehlen, dass Sie os.path.isdir() zu testen, anstatt os.path.exists() .

>>> os.path.exists('/tmp/dirname')
True
>>> os.path.exists('/tmp/dirname/filename.etc')
True
>>> os.path.isdir('/tmp/dirname/filename.etc')
False
>>> os.path.isdir('/tmp/fakedirname')
False

Wenn Sie haben:

>>> dir = raw_input(":: ")

Und eine törichte Benutzereingabe:

:: /tmp/dirname/filename.etc

... Am Ende haben Sie ein Verzeichnis mit dem Namen filename.etc wenn Sie dieses Argument an os.makedirs() wenn Sie den Test mit os.path.exists() .

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X