Wie kann ich ein verschachteltes Verzeichnis in Python erstellen?

Was ist der eleganteste Weg zu prüfen, ob das Verzeichnis, in das eine Datei geschrieben wird, existiert, und wenn nicht, das Verzeichnis mit Python erstellen? Hier ist was ich versucht habe:

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 os.path.exists (danke kanja, Blair und Douglas) vermisst. Das habe ich jetzt:

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

Gibt es eine Flagge für “offen”, die das automatisch macht?

Ich sehe zwei Antworten mit guten Eigenschaften, jede mit einem kleinen Fehler, also werde ich darauf eingehen:

Versuchen Sie os.path.exists und betrachten Sie os.makedirs für die Erstellung.

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

Wie in Kommentaren und anderswo angemerkt, gibt es eine Race-Bedingung – wenn das Verzeichnis zwischen den os.path.exists und den os.makedirs Aufrufen erstellt wird, wird os.makedirs mit einem OSError . Unglücklicherweise ist das OSError und Fortsetzen nicht idiotensicher, da ein Fehler beim Erstellen des Verzeichnisses aufgrund anderer Faktoren wie unzureichende Berechtigungen, vollständige Festplatte usw. ignoriert wird.

Eine Option wäre, den OSError und den eingebetteten Fehlercode zu untersuchen (siehe Gibt es einen plattformübergreifenden Weg, Informationen aus Pythons OSError zu erhalten ):

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

Alternativ könnte es eine zweite os.path.exists , aber angenommen, eine andere erstellt das Verzeichnis nach der ersten Überprüfung, dann entfernt es vor der zweiten – wir könnten immer noch täuschen.

Abhängig von der Anwendung kann die Gefahr von gleichzeitigen Operationen mehr oder weniger als die Gefahr durch andere Faktoren wie Dateiberechtigungen sein. Der Entwickler müsste vor der Auswahl einer Implementierung mehr über die jeweilige zu entwickelnde Anwendung und ihre erwartete Umgebung wissen.

Python 3.5+:

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

pathlib.Path.mkdir wie oben verwendet, erstellt rekursiv das Verzeichnis und triggers keine Ausnahme aus, wenn das Verzeichnis bereits existiert. Wenn Sie nicht möchten, dass die Eltern erstellt werden, überspringen Sie das Argument ” parents .

Python 3.2+:

pathlib :

Wenn Sie können, installieren Sie das aktuelle pathlib Backport namens pathlib2 . Installieren Sie nicht den älteren nicht gepflegten Backport namens pathlib . Beziehen Sie sich als Nächstes auf den obigen Abschnitt Python 3.5+ und verwenden Sie dasselbe.

Wenn Python 3.4 verwendet wird, obwohl es mit pathlib , fehlt die nützliche exist_ok Option. Der Backport soll eine neuere und mkdir Implementierung von mkdir die diese fehlende Option beinhaltet.

Verwenden von os :

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

os.makedirs wie oben verwendet, erstellt rekursiv das Verzeichnis und triggers keine Ausnahme aus, wenn das Verzeichnis bereits existiert. Es hat das optionale Argument exist_ok nur bei Verwendung von Python 3.2+ mit dem Standardwert False . Dieses Argument existiert in Python 2.x bis 2.7 nicht. Daher ist eine manuelle Ausnahmebehandlung wie bei Python 2.7 nicht erforderlich.

Python 2.7+:

pathlib :

Wenn Sie können, installieren Sie das aktuelle pathlib Backport namens pathlib2 . Installieren Sie nicht den älteren nicht gepflegten Backport namens pathlib . Beziehen Sie sich als Nächstes auf den obigen Abschnitt Python 3.5+ und verwenden Sie dasselbe.

Verwenden von os :

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

Während eine naive Lösung zuerst os.path.isdir gefolgt von os.makedirs , kehrt die obige Lösung die Reihenfolge der beiden Operationen um. Auf diese Weise verhindert es eine allgemeine Race-Bedingung, die mit einem doppelten Versuch des Erstellens des Verzeichnisses zu tun hat, und disambiguiert auch Dateien von Verzeichnissen.

Beachten Sie, dass die Erfassung der Ausnahme und die Verwendung von errno nur von begrenztem Nutzen sind, da OSError: [Errno 17] File exists , dh errno.EEXIST , wird sowohl für Dateien als auch für Verzeichnisse errno.EEXIST . Es ist zuverlässiger, einfach zu überprüfen, ob das Verzeichnis existiert.

Alternative:

mkpath erstellt das verschachtelte Verzeichnis und macht nichts, wenn das Verzeichnis bereits existiert. Dies funktioniert in Python 2 und 3.

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

Pro Bug 10948 ist eine schwerwiegende Einschränkung dieser Alternative, dass sie nur einmal pro Python-process für einen bestimmten Pfad funktioniert. Mit anderen Worten, wenn Sie es verwenden, um ein Verzeichnis zu erstellen, dann löschen Sie das Verzeichnis von innerhalb oder außerhalb von Python, dann verwenden mkpath erneut mkpath , um das gleiche Verzeichnis neu zu erstellen, mkpath wird einfach seine ungültigen zwischengespeicherten Informationen über die vorherige mkpath des Verzeichnisses verwenden wird das Verzeichnis nicht wirklich neu erstellen. Im Gegensatz dazu ist os.makedirs nicht auf einen solchen Cache angewiesen. Diese Einschränkung kann für einige Anwendungen in Ordnung sein.


In Bezug auf den Modus des Verzeichnisses finden Sie in der Dokumentation, wenn Sie sich darum kümmern.

Mit try except und dem richtigen Fehlercode von errrno Modul wird die Race Condition beseitigt 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. Auf der anderen Seite wird jeder andere Fehler gemeldet. Wenn Sie beispielsweise zuvor dir ‘a’ erstellen und alle Berechtigungen daraus entfernen, erhalten Sie einen OSError , der mit errno.EACCES (Berechtigung verweigert, Fehler 13).

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

 >>> 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 dumme Benutzereingabe:

 :: /tmp/dirname/filename.etc 

… Sie werden mit einem Verzeichnis namens os.makedirs() enden, wenn Sie dieses Argument an os.makedirs() wenn Sie mit os.path.exists() testen.

Überprüfen Sie os.makedirs : (Es stellt sicher, dass der vollständige Pfad existiert.)
Um die Tatsache zu verarbeiten, dass das Verzeichnis möglicherweise vorhanden ist, fangen Sie OSError ab. (Wenn exist_ok False ist (der Standardwert), wird ein OSError ausgetriggers, wenn das Zielverzeichnis bereits existiert.)

 import os try: os.makedirs('./path/to/somewhere') except OSError: pass 

Einblicke in die Besonderheiten dieser Situation

Sie geben eine bestimmte Datei an einem bestimmten Pfad und Sie ziehen das Verzeichnis aus dem Dateipfad. Nachdem Sie sichergestellt haben, dass Sie das Verzeichnis haben, versuchen Sie, eine Datei zum Lesen zu öffnen. Um diesen Code zu kommentieren:

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

Wir wollen verhindern, dass die eingebaute function überschrieben wird. Außerdem ist filepath oder vielleicht fullfilepath wahrscheinlich ein besserer semantischer Name als filename daher wäre dies besser geschrieben:

 import os filepath = '/my/directory/filename.txt' directory = os.path.dirname(filepath) 

Ihr Endziel ist es, diese Datei zu öffnen, die Sie ursprünglich für das Schreiben angeben, aber Sie nähern sich im Wesentlichen diesem Ziel (basierend auf Ihrem Code) wie folgt, das die Datei zum Lesen öffnet:

 if not os.path.exists(directory): os.makedirs(directory) f = file(filename) 

Annahme der Öffnung zum Lesen

Warum sollten Sie ein Verzeichnis für eine Datei erstellen, von der Sie erwartet haben, dass sie dort ist und in der Lage zu lesen?

Versuchen Sie einfach, die Datei zu öffnen.

 with open(filepath) as my_file: do_stuff(my_file) 

Wenn das Verzeichnis oder die Datei nicht vorhanden ist, erhalten Sie einen IOError mit einer zugehörigen Fehlernummer: errno.ENOENT zeigt unabhängig von Ihrer Plattform auf die richtige Fehlernummer. Sie können es fangen, wenn Sie möchten, zum Beispiel:

 import errno try: with open(filepath) as my_file: do_stuff(my_file) except IOError as error: if error.errno == errno.ENOENT: print 'ignoring error because directory or file is not there' else: raise 

Vorausgesetzt, wir öffnen zum Schreiben

Das ist wahrscheinlich, was du willst.

In diesem Fall stehen wir wahrscheinlich keinen Rassenbedingungen gegenüber. Also tun Sie einfach so, wie Sie waren, aber beachten Sie, dass Sie zum Schreiben müssen Sie mit dem w Modus öffnen (oder a Anfügen). Es ist auch eine bewährte Vorgehensweise von Python, den Kontextmanager zum Öffnen von Dateien zu verwenden.

 import os if not os.path.exists(directory): os.makedirs(directory) with open(filepath, 'w') as my_file: do_stuff(my_file) 

Nehmen wir an, wir haben mehrere Python-processe, die versuchen, alle ihre Daten in dasselbe Verzeichnis zu stellen. Dann können wir Streit über die Erstellung des Verzeichnisses haben. In diesem Fall ist es am besten, den makedirs Aufruf in einen try-except-Block zu makedirs .

 import os import errno if not os.path.exists(directory): try: os.makedirs(directory) except OSError as error: if error.errno != errno.EEXIST: raise with open(filepath, 'w') as my_file: do_stuff(my_file) 

Ab Python 3.5 hat pathlib.Path.mkdir ein exist_ok Flag:

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

Dies erstellt rekursiv das Verzeichnis und triggers keine Ausnahme aus, wenn das Verzeichnis bereits existiert.

(So ​​wie os.makedirs ein exists_ok Flag hat, das mit Python 3.2 beginnt).

Ich habe Folgendes niedergelegt. Es ist jedoch nicht absolut narrensicher.

 import os dirname = 'create/me' try: os.makedirs(dirname) except OSError: if os.path.exists(dirname): # We are nearly safe pass else: # There was an error on creation, so make sure we know about it raise 

Nun, wie ich schon sagte, ist dies nicht wirklich narrensicher, weil wir die Möglichkeit haben, das Verzeichnis nicht zu erstellen, und einen anderen process, der es während dieses Zeitraums erstellt.

Probieren Sie die function os.path.exists aus

 if not os.path.exists(dir): os.mkdir(dir) 

Überprüfen Sie, ob ein Verzeichnis existiert und erstellen Sie es gegebenenfalls?

Die direkte Antwort darauf ist eine einfache Situation, in der Sie nicht erwarten, dass andere Benutzer oder processe Ihr Verzeichnis durcheinander bringen:

 if not os.path.exists(d): os.makedirs(d) 

oder wenn das Verzeichnis Race Conditions unterliegt (dh wenn nach der Überprüfung der Pfad existiert, könnte etwas anderes bereits gemacht worden sein):

 import errno try: os.makedirs(d) except OSError as exception: if exception.errno != errno.EEXIST: raise 

Aber vielleicht ist ein noch besserer Ansatz, das Ressourcenkonfliktproblem zu umgehen, indem temporäre Verzeichnisse über tempfile :

 import tempfile d = tempfile.mkdtemp() 

Hier ist das Wesentliche aus dem Online-Dokument:

 mkdtemp(suffix='', prefix='tmp', dir=None) User-callable function to create and return a unique temporary directory. The return value is the pathname of the directory. The directory is readable, writable, and searchable only by the creating user. Caller is responsible for deleting the directory when done with it. 

Neu in Python 3.5: pathlib.Path mit exist_ok

Es gibt ein neues Path Objekt (ab 3.4) mit vielen Methoden, die man mit Pfaden verwenden möchte – einer davon ist mkdir .

(Im Kontext verfolge ich meine wöchentliche Vertretung mit einem Skript. Hier sind die relevanten Teile des Codes aus dem Skript, die es mir ermöglichen, Stack Overflow mehr als einmal pro Tag für die gleichen Daten zu vermeiden.)

Zuerst die relevanten Importe:

 from pathlib import Path import tempfile 

Wir müssen uns jetzt nicht mit os.path.join befassen – os.path.join einfach os.path.join mit einem / :

 directory = Path(tempfile.gettempdir()) / 'sodata' 

Dann exist_ok ich sicher, dass das Verzeichnis existiert – das Argument exist_ok in Python 3.5:

 directory.mkdir(exist_ok=True) 

Hier ist der relevante Teil der Dokumentation :

Wenn exist_ok true ist, werden FileExistsError Exceptions ignoriert (dasselbe Verhalten wie der Befehl POSIX mkdir -p ), aber nur, wenn die letzte Pfadkomponente keine vorhandene Nicht-Verzeichnis-Datei ist.

Hier ist ein bisschen mehr von dem Skript – in meinem Fall bin ich nicht einer Race Condition ausgesetzt, ich habe nur einen process, der das Verzeichnis (oder die enthaltenen Dateien) erwartet, und ich habe nichts zu entfernen das Verzeichnis.

 todays_file = directory / str(datetime.datetime.utcnow().date()) if todays_file.exists(): logger.info("todays_file exists: " + str(todays_file)) df = pd.read_json(str(todays_file)) 

Pfadobjekte müssen in str bevor andere APIs, die str Pfade erwarten, sie verwenden können.

Vielleicht sollten Pandas aktualisiert werden, um Instanzen der abstrakten Basisklasse os.PathLike zu akzeptieren.

In Python 3.4 können Sie auch das brandneue pathlib Modul verwenden :

 from pathlib import Path path = Path("/my/directory/filename.txt") try: if not path.parent.exists(): path.parent.mkdir(parents=True) except OSError: # handle error; you can also catch specific errors like # FileExistsError and so on. 

Die relevante Python-Dokumentation schlägt die Verwendung des EAFP-Codierungsstils vor (Leichter um Vergebung bitten als Erlaubnis) . Dies bedeutet, dass der Code

 try: os.makedirs(path) except OSError as exception: if exception.errno != errno.EEXIST: raise else: print "\nBE CAREFUL! Directory %s already exists." % path 

ist besser als die Alternative

 if not os.path.exists(path): os.makedirs(path) else: print "\nBE CAREFUL! Directory %s already exists." % path 

Die Dokumentation suggeriert dies genau wegen der in dieser Frage diskutierten Race Condition. Darüber hinaus gibt es, wie andere hier erwähnen, einen performancesvorteil beim einmaligen Abfragen des Betriebssystems anstelle des Doppelten. Schließlich kann das Argument, das möglicherweise zugunsten des zweiten Codes vorgeschlagen wird, in einigen Fällen – wenn der Entwickler die Umgebung kennt, in der die Anwendung läuft – nur in dem speziellen Fall befürwortet werden, für den das Programm eine private Umgebung eingerichtet hat selbst (und andere Instanzen des gleichen Programms).

Selbst in diesem Fall ist dies eine schlechte Übung und kann zu einem langen nutzlosen Debugging führen. Zum Beispiel sollte die Tatsache, dass wir die Berechtigungen für ein Verzeichnis festgelegt haben, uns nicht mit den Impressionsrechten belassen, die für unsere Zwecke geeignet sind. Ein übergeordnetes Verzeichnis könnte mit anderen Berechtigungen bereitgestellt werden. Im Allgemeinen sollte ein Programm immer korrekt funktionieren und der Programmierer sollte keine bestimmte Umgebung erwarten.

Sie können mkpath

 # Create a directory and any missing ancestor directories. # If the directory already exists, do nothing. from distutils.dir_util import mkpath mkpath("test") 

Beachten Sie, dass damit auch die Vorgängerverzeichnisse erstellt werden.

Es funktioniert für Python 2 und 3.

In Python3 unterstützt os.makedirs die Einstellung exist_ok . Die Standardeinstellung ist False . OSError bedeutet, dass ein OSError wird, wenn das Zielverzeichnis bereits existiert. Wenn Sie exist_ok auf True , wird OSError (Verzeichnis existiert) ignoriert und das Verzeichnis wird nicht erstellt.

 os.makedirs(path,exist_ok=True) 

In Python2 unterstützt os.makedirs die Einstellung von exist_ok . Sie können den Ansatz in heikki-toivonen’s Antwort verwenden :

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

Für eine IPython.utils.path.ensure_dir_exists() können Sie IPython.utils.path.ensure_dir_exists() :

 from IPython.utils.path import ensure_dir_exists ensure_dir_exists(dir) 

Aus der Dokumentation : Stellen Sie sicher, dass ein Verzeichnis existiert. Wenn es nicht existiert, versuchen Sie es zu erstellen und schützen Sie sich vor einer Race Condition, wenn ein anderer process dasselbe tut.

Ich benutze os.path.exists() , hier ist ein Python 3-Skript, das verwendet werden kann, um zu prüfen, ob ein Verzeichnis existiert, eines zu erstellen, wenn es nicht existiert, und es zu löschen, falls es existiert (falls gewünscht).

Es fordert Benutzer zur Eingabe des Verzeichnisses auf und kann leicht modifiziert werden.

Ich fand dieses Q / A und ich war anfangs verwirrt über einige Fehler und Fehler, die ich bekam. Ich arbeite in Python 3 (v.3.5 in einer virtuellen Anaconda-Umgebung auf einem Arch Linux x86_64-System).

Betrachten Sie diese Verzeichnisstruktur:

 └── output/ ## dir ├── corpus ## file ├── corpus2/ ## dir └── subdir/ ## dir 

Hier sind meine Experimente / Notizen, die die Dinge verdeutlichen:

 # ---------------------------------------------------------------------------- # [1] https://stackoverflow.com/questions/273192/how-can-i-create-a-directory-if-it-does-not-exist import pathlib """ Notes: 1. Include a trailing slash at the end of the directory path ("Method 1," below). 2. If a subdirectory in your intended path matches an existing file with same name, you will get the following error: "NotADirectoryError: [Errno 20] Not a directory:" ... """ # Uncomment and try each of these "out_dir" paths, singly: # ---------------------------------------------------------------------------- # METHOD 1: # Re-running does not overwrite existing directories and files; no errors. # out_dir = 'output/corpus3' ## no error but no dir created (missing tailing /) # out_dir = 'output/corpus3/' ## works # out_dir = 'output/corpus3/doc1' ## no error but no dir created (missing tailing /) # out_dir = 'output/corpus3/doc1/' ## works # out_dir = 'output/corpus3/doc1/doc.txt' ## no error but no file created (os.makedirs creates dir, not files! ;-) # out_dir = 'output/corpus2/tfidf/' ## fails with "Errno 20" (existing file named "corpus2") # out_dir = 'output/corpus3/tfidf/' ## works # out_dir = 'output/corpus3/a/b/c/d/' ## works # [2] https://docs.python.org/3/library/os.html#os.makedirs # Uncomment these to run "Method 1": #directory = os.path.dirname(out_dir) #os.makedirs(directory, mode=0o777, exist_ok=True) # ---------------------------------------------------------------------------- # METHOD 2: # Re-running does not overwrite existing directories and files; no errors. # out_dir = 'output/corpus3' ## works # out_dir = 'output/corpus3/' ## works # out_dir = 'output/corpus3/doc1' ## works # out_dir = 'output/corpus3/doc1/' ## works # out_dir = 'output/corpus3/doc1/doc.txt' ## no error but creates a .../doc.txt./ dir # out_dir = 'output/corpus2/tfidf/' ## fails with "Errno 20" (existing file named "corpus2") # out_dir = 'output/corpus3/tfidf/' ## works # out_dir = 'output/corpus3/a/b/c/d/' ## works # Uncomment these to run "Method 2": #import os, errno #try: # os.makedirs(out_dir) #except OSError as e: # if e.errno != errno.EEXIST: # raise # ---------------------------------------------------------------------------- 

Fazit: “Methode 2” ist meiner Meinung nach robuster.

[1] Wie kann ich ein Verzeichnis erstellen, wenn es nicht existiert?

[2] https://docs.python.org/3/library/os.html#os.makedirs

Ich habe die Antworten von Heikki Toivonen und ABB gesehen und an diese Variante gedacht.

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

Sie können os.listdir dafür verwenden:

 import os if 'dirName' in os.listdir('parentFolderPath') print('Directory Exists') 

Wenn Sie mit Datei-I / O arbeiten, ist es wichtig zu beachten

TOCTTOU (Uhrzeit der Überprüfung bis Zeitpunkt der Nutzung)

Eine Überprüfung mit if und dann späterem Lesen oder Schreiben kann zu einer unbehandelten E / A-Ausnahme führen. Der beste Weg, es zu tun ist:

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

Wenn Sie Folgendes beachten:

 os.path.isdir('/tmp/dirname') 

bedeutet, ein Verzeichnis (Pfad) existiert UND ist ein Verzeichnis. Also für mich tut dieser Weg, was ich brauche. So kann ich sicherstellen, dass es sich um einen Ordner (keine Datei) handelt und existiert.

Verwenden Sie diesen Befehl check und erstellen Sie dir

  if not os.path.isdir(test_img_dir): os.mkdir(str("./"+test_img_dir)) 

Rufen create_dir() am Einstiegspunkt Ihres Programms / Projekts die function create_dir() auf.

 import os def create_dir(directory): if not os.path.exists(directory): print('Creating Directory '+directory) os.makedirs(directory) create_dir('Project directory') 
 import os if os.path.isfile(filename): print "file exists" else: "Your code here" 

Wo Ihr Code hier ist, benutzen Sie den (Touch) -Befehl

Dies überprüft, ob die Datei vorhanden ist, wenn sie nicht vorhanden ist, dann wird sie erstellt.