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)

110voto

Douglas Mayle Punkte 19645

Siehe os.makedirs : (Er stellt sicher, dass der vollständige Pfad existiert.)
Um mit der Tatsache umzugehen, dass das Verzeichnis existieren könnte, fangen Sie OSError . (Wenn exist_ok es False (der Standard), eine OSError wird ausgelöst, wenn das Zielverzeichnis bereits existiert).

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

26 Stimmen

Mit try/except werden Sie Fehler bei der Erstellung von Verzeichnissen maskieren, wenn das Verzeichnis nicht existiert, aber aus irgendeinem Grund nicht erstellt werden kann

87voto

gone Punkte 4038

Versuchen Sie die os.path.exists Funktion

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

63voto

Einblicke in die Besonderheiten dieser Situation

Sie geben eine bestimmte Datei unter einem bestimmten Pfad an und ziehen das Verzeichnis aus dem Dateipfad. Nachdem Sie sich vergewissert 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 vermeiden, die eingebaute Funktion zu überschreiben, dir . Auch, filepath oder vielleicht fullfilepath ist wahrscheinlich ein besserer semantischer Name als filename damit dies besser geschrieben werden kann:

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

Ihr Endziel ist es, diese Datei zum Schreiben zu öffnen, aber Sie nähern sich diesem Ziel (auf der Grundlage Ihres Codes) im Wesentlichen wie folgt, wodurch die Datei für Lesen :

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

Vorausgesetzt, dass die Öffnung zum Lesen

Warum sollten Sie ein Verzeichnis für eine Datei anlegen, von der Sie erwarten, dass sie dort vorhanden ist und gelesen werden kann?

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 die Meldung IOError mit einer zugehörigen Fehlernummer: errno.ENOENT verweist unabhängig von Ihrer Plattform auf die richtige Fehlernummer. Sie können ihn zum Beispiel abfangen, wenn Sie wollen:

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

Angenommen, wir öffnen uns zum Schreiben

Dies ist wahrscheinlich was ihr wollt.

In diesem Fall haben wir es wahrscheinlich nicht mit einer Wettlaufsituation zu tun. Machen Sie also einfach weiter wie bisher, aber beachten Sie, dass Sie zum Schreiben mit der Option w Modus (oder a zum Anhängen). Es ist auch eine bewährte Python-Praxis, 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)

Angenommen, wir haben mehrere Python-Prozesse, die versuchen, alle ihre Daten in dasselbe Verzeichnis zu legen. Dann kann es zu Konflikten bei der Erstellung des Verzeichnisses kommen. In diesem Fall ist es am besten, die makedirs Aufruf in einem try-except-Block.

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)

44voto

Ali Afshar Punkte 39615

Ich habe das Folgende niedergeschrieben. Es ist allerdings nicht völlig idiotensicher.

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

Wie gesagt, das ist nicht wirklich sicher, denn es besteht die Möglichkeit, dass die Erstellung des Verzeichnisses fehlschlägt und ein anderer Prozess es in dieser Zeit erstellt.

35voto

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

Die direkte Antwort auf diese Frage ist, dass Sie von einer einfachen Situation ausgehen, in der Sie nicht erwarten, dass andere Benutzer oder Prozesse an Ihrem Verzeichnis herumspielen:

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

o wenn das Erstellen des Verzeichnisses Wettlaufbedingungen unterliegt (d.h. wenn nach der Überprüfung der Existenz des Pfades etwas anderes es bereits erstellt haben könnte), tun Sie dies:

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

Aber vielleicht ist es sogar besser, das Problem der Ressourcenkonkurrenz zu umgehen, indem man temporäre Verzeichnisse über tempfile :

import tempfile

d = tempfile.mkdtemp()

Hier sind die wichtigsten Informationen 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 con exist_ok

Es gibt eine neue Path Objekt (ab 3.4) mit vielen Methoden, die man mit Pfaden verwenden möchte - eine davon ist mkdir .

(Zum Vergleich: Ich verfolge meine wöchentliche Vertretung mit einem Skript. Hier sind die relevanten Teile des Codes aus dem Skript, die es mir ermöglichen, zu vermeiden, Stack Overflow mehr als einmal am Tag für dieselben Daten zu besuchen).

Zunächst zu den relevanten Einfuhren:

from pathlib import Path
import tempfile

Wir müssen uns nicht mit os.path.join jetzt - verbinden Sie einfach Pfadteile mit einem / :

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

Dann stelle ich idempotent sicher, dass das Verzeichnis existiert - die exist_ok Argument taucht in Python 3.5 auf:

directory.mkdir(exist_ok=True)

Hier ist der relevante Teil der Dokumentation :

Si exist_ok wahr ist, FileExistsError Ausnahmen werden ignoriert (gleiches Verhalten wie bei der POSIX mkdir -p Befehl), aber nur, wenn die letzte Pfadkomponente keine bestehende Nicht-Verzeichnisdatei ist.

Hier ist ein wenig mehr von dem Skript - in meinem Fall unterliege ich keiner Race Condition, ich habe nur einen Prozess, der erwartet, dass das Verzeichnis (oder die darin enthaltenen Dateien) vorhanden ist, und ich habe nichts, das versucht, das Verzeichnis zu entfernen.

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))

Path Objekte müssen dazu gezwungen werden str vor anderen APIs, die eine str Pfade können sie nutzen.

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

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