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)

21voto

kavadias Punkte 1007

El einschlägige Python-Dokumentation schlägt die Verwendung des EAFP-Kodierungsstil (Easier to Ask for Forgiveness than Permission) . 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

besser ist als die Alternative

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

In der Dokumentation wird dies genau wegen der in dieser Frage erörterten Race Condition vorgeschlagen. Darüber hinaus gibt es, wie andere hier erwähnen, einen Leistungsvorteil, wenn das Betriebssystem einmal statt zweimal abgefragt wird. Schließlich kann das Argument, das möglicherweise in einigen Fällen für den zweiten Code vorgebracht wird - wenn der Entwickler die Umgebung kennt, in der die Anwendung läuft - nur in dem speziellen Fall befürwortet werden, dass das Programm eine private Umgebung für sich selbst (und andere Instanzen desselben Programms) eingerichtet hat.

Selbst in diesem Fall ist dies eine schlechte Praxis und kann zu einer langen, nutzlosen Fehlersuche führen. Beispielsweise sollte die Tatsache, dass wir die Berechtigungen für ein Verzeichnis festlegen, nicht den Eindruck erwecken, dass die Berechtigungen für unsere Zwecke angemessen festgelegt sind. Ein übergeordnetes Verzeichnis könnte mit anderen Berechtigungen gemountet werden. Im Allgemeinen sollte ein Programm immer korrekt funktionieren und der Programmierer sollte nicht eine bestimmte Umgebung erwarten.

14voto

Victoria Stuart Punkte 3912

Ich bin auf diese Frage gestoßen, nachdem ich mich über einige Fehler bei der Arbeit mit Verzeichnissen in Python gewundert habe. Ich arbeite mit 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 zur Klärung beitragen:

# ----------------------------------------------------------------------------
# [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: Meiner Meinung nach ist "Methode 2" robuster.

[1] Wie kann ich ein verschachteltes Verzeichnis sicher erstellen?

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

0 Stimmen

Der Grund, warum Ihre Methode 1 nicht funktioniert, ist der Aufruf von os.dirname. Ohne diesen funktioniert Methode 1 wie erwartet.

13voto

Dennis Golomazov Punkte 14467

Sie können verwenden 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 dabei auch die Vorgängerverzeichnisse erstellt werden.

Es funktioniert für Python 2 und 3.

11voto

Wenn Sie eine Datei in einen variablen Pfad schreiben, können Sie dies für den Pfad der Datei verwenden, um sicherzustellen, dass die übergeordneten Verzeichnisse erstellt werden.

from pathlib import Path

path_to_file = Path("zero/or/more/directories/file.ext")
parent_directory_of_file = path_to_file.parent
parent_directory_of_file.mkdir(parents=True, exist_ok=True)

Funktioniert auch, wenn path_to_file es file.ext (null Verzeichnisse tief).

Ver pathlib.PurePath.parent y pathlib.Path.mkdir .

10voto

Warum nicht das Modul subprocess verwenden, wenn es auf einem Rechner läuft, der den Befehl mkdir con -p Option ? Funktioniert mit Python 2.7 und Python 3.6

from subprocess import call
call(['mkdir', '-p', 'path1/path2/path3'])

Das sollte bei den meisten Systemen genügen.

In Situationen, in denen die Portabilität keine Rolle spielt (z. B. bei der Verwendung von Docker), ist die Lösung eine saubere 2-Zeilen-Lösung. Sie müssen auch keine Logik hinzufügen, um zu prüfen, ob Verzeichnisse existieren oder nicht. Und schließlich ist es sicher, ohne Nebenwirkungen erneut ausgeführt zu werden

Wenn Sie eine Fehlerbehandlung benötigen:

from subprocess import check_call
try:
    check_call(['mkdir', '-p', 'path1/path2/path3'])
except:
    handle...

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