Cum pot crea condiții de siguranță o imbricate director?

Ceea ce este cel mai elegant mod de a verifica dacă directorul unui fișier este de gând să fie scrise pentru a exista, și dacă nu, creați directorul folosind Python? Aici este ceea ce am încercat:

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)

Cumva, am pierdut `os.calea.există (datorită kanja, Blair, și Douglas). Aceasta este ceea ce am acum:

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

Este acolo un steag pentru "open", care face acest lucru în mod automat?

Comentarii la întrebare (6)
Soluția

Eu văd două răspunsuri cu calități bune, fiecare cu un mic defect, așa că vor da mi iau pe asta:

Încerca os.calea.există, și ia în considerare os.makedirs pentru crearea.

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

După cum sa menționat în comentarii și în altă parte, acolo's o condiție de rulare – dacă directorul este creat între os.calea.există " și " sistem de operare.makedirs apeluri, os.makedirs va eșua, cu o OSError. Din păcate, pătură-prinderea OSError și continuă nu este foarte simplu de manevrat, deoarece va ignora un eșec pentru a crea directorul din cauza altor factori, cum ar fi permisiuni insuficiente, plin de disc, etc.

O opțiune ar fi să prindă OSError și de a examina încorporat cod de eroare (a se vedea Este un cross-platform mod de a obține informații de la Python OSError):

import os, errno

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

Alternativ, ar putea fi un al doilea sistem de operare.calea.există, dar să presupunem că un alt creat directorul după prima verificare, apoi a scos-o înainte de cel de-al doilea – am putea fi păcălit.

În funcție de aplicație, pericolul de operațiuni simultane poate fi mai mult sau mai puțin decât pericolul reprezentat de alți factori, cum ar fi permisiunile de fișiere. Dezvoltatorul ar trebui să știu mai multe despre aplicație special dezvoltată și temperatura mediului înainte de a alege o implementare.

Versiunile moderne de Python îmbunătăți acest cod destul de un pic, atât prin expunerea FileExistsError (în 3.3+)...

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

...și permițând un cuvânt cheie argument pentru os.makedirs "numit" exist_ok (în 3.2+).

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

Python 3.5+:

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

pathlib.Calea.mkdir cum este utilizat de mai sus recursiv creează directorul și nu ridică o excepție dacă directorul exista deja. Dacă tu nu't nevoie sau doresc părinții să fie creat, skip "părinții" argument.

Python 3.2+:

Folosind pathlib:

Dacă aveți posibilitatea, montați curent pathlib backport nume pathlib2. Nu instalați în vârstă neîntreținute backport nume pathlib. Apoi, se referă la Piton de 3,5+ secțiunea de mai sus și să-l utilizați la fel.

Dacă folosind Python 3.4, chiar dacă acesta vine cu pathlib, este lipsă de utilexist_okopțiune. La backport este destinat să ofere o nouă și superioară punerea în aplicare amkdir` care include această opțiune de lipsă.

Folosind os:

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

os.makedirs cum este utilizat de mai sus recursiv creează directorul și nu ridică o excepție dacă directorul exista deja. Are opțional exist_ok argument numai dacă utilizarea Python 3.2+, cu o valoare implicită de "False". Acest argument nu există în Python 2.x până la 2.7. Ca atare, nu este nevoie de manual de manipulare excepție și cu Python 2.7.

Python 2.7+:

Folosind pathlib:

Dacă aveți posibilitatea, montați curent pathlib backport nume pathlib2. Nu instalați în vârstă neîntreținute backport nume pathlib. Apoi, se referă la Piton de 3,5+ secțiunea de mai sus și să-l utilizați la fel.

Folosind os:

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

În timp ce o soluție naiv poate prima utilizare os.calea.isdir urmat de os.makedirs, soluția de mai sus inversează ordinea celor două operațiuni. Procedând astfel, se previne o cursă comună condiția de a avea de-a face cu un duplicat tentativa de a crea directorul, și, de asemenea, separă fișiere din directoare.

Rețineți că capturarea excepție și folosirea errno va fieste de o utilitate limitată din cauzaOSError: [errno va fi 17] există Fișier, adicăerrno va fi.EEXIST`, este crescut atât pentru fișiere și directoare. Este mult mai fiabile pur și simplu pentru a verifica dacă directorul nu există.

Alternative:

mkpath creează imbricate director, și nu face nimic dacă directorul exista deja. Acest lucru funcționează în ambele Python 2 și 3.

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

Pe Bug 10948, o limitare severă de această alternativă este că ea funcționează doar o dată pe python proces pentru o anumită cale. Cu alte cuvinte, dacă îl folosiți pentru a crea un director, apoi ștergeți directorul din interiorul sau din exteriorul Python, apoi utilizați mkpath din nou pentru a recrea același director,mkpathva, pur și simplu, în tăcere, își folosească invalid info cache de a fi creat anterior director, și de fapt, nu vor face din nou directorul. În contrast,os.makedirs` nu't să se bazeze pe orice astfel de cache. Această limitare poate fi bine pentru unele aplicații.


Cu privire la directorul's modul, vă rugăm să consultați documentația dacă îți pasă de ea.

Comentarii (10)

Folosind încercați cu excepția și dreptul de codul de eroare de errno va fi modul scapa de starea de rasă și este cross-platform:

import os
import errno

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

Cu alte cuvinte, vom încerca pentru a crea directoare, dar dacă ele există deja am ignora eroare. Pe de altă parte, orice alte erori raportate. De exemplu, dacă veți crea dir 'un' în prealabil și elimina toate permisiunile de la ea, veți obține o OSErrora ridicat cu errno va fi.EACCES (Permission denied, eroare 13).

Comentarii (20)

Personal nu mi-ar recomandăm să utilizați os.calea.isdir() pentru a testa în loc de os.calea.există().

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

Dacă aveți:

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

Și o prostie de intrare de utilizator:

:: /tmp/dirname/filename.etc

... Ai're de gând să se încheie cu un director cu numele filename.etc, atunci când trece ca argument pentruos.makedirs()dacă testați cuos.calea.există()`.

Comentarii (3)

Verific os.makedirs: (Se face sigur calea completă există.) Să se ocupe de faptul directorul ar putea exista, prinde OSError. (Dacăexist_okeste "Fals" (implicit), oOSError` este crescut în cazul în directorul țintă există deja.)

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

Pornind de la Python 3.5, pathlib.Calea.mkdir a o 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)

Acest recursiv creează directorul și nu ridică o excepție dacă directorul exista deja.

(la fel ca os.makedirs are o exist_okpavilion pornind de la python 3.2.e.gos.makedirs(cale, exist_ok=True)`)

Comentarii (0)

Perspective pe specificul de această situație

Vă dau un anumit fișier la o anumită cale și trage director din calea de fișier. Apoi, după asigurându-vă că aveți director, încercarea de a deschide un fișier pentru citire. Pentru a comenta pe acest cod:

filename = "/mea/director/fisier.txt" dir = os.calea.dirname(filename)

Vrem pentru a evita suprascrierea funcție nativă, dir. De asemenea, filepath sau poate fullfilepath este, probabil, o mai bună semantic numele de filename deci asta ar fi mai bine scris:

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

Obiectivul dvs. final este de a deschide acest fișier, inițial stat, pentru scris, dar're în esență, să se apropie de acest obiectiv (bazat pe cod), cum ar fi acest lucru, care se deschide fișierul pentru lectură:

dacă nu sistemul de operare.calea.există(director): sistem de operare.makedirs(director) f = file(fisier)

Presupunând deschiderea pentru citire

De ce ai face un director pentru un fișier care te aștepți să fie acolo și să fie capabil să citească?

Doar încercarea de a deschide fișierul.

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

Dacă directorul sau fișierul este't acolo,'ll o IOError cu asociat un număr de eroare:errno va fi.ENOENT` va indica corect numărul de eroare, indiferent de platforma. Puteți să-l prind, dacă doriți, de exemplu:

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

Presupunând că ne-am're de deschidere pentru scriere

Acest lucru este probabil ceea ce're doresc.

În acest caz, noi, probabil, nu't cu care se confruntă orice condiții de rasă. Așa că fă cum ai fost tu, dar rețineți că pentru scris, aveți nevoie pentru a deschide cu " w "modul (sau" a " pentru a adăuga). L's, de asemenea, un Piton mai bună practică de a utiliza contextul manager pentru deschiderea fișierelor.

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

Cu toate acestea, spune că avem mai multe Python procese care încearcă să pună toate datele lor în același director. Atunci am putea avea dispută asupra creației de director. În acest caz, se's cel mai bun pentru a încheia makedirs apel la o probă, cu excepția bloc.

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)
Comentarii (0)

Încerca os.calea.există funcția

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

Mi-am pus următoarele jos. L'nu e foarte simplu de lucrat, deși.

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

Acum, cum am spus, acest lucru nu este chiar foarte simplu de manevrat, pentru că avem posibilitatea de a nu crea directorul, și un alt proces crearea în această perioadă.

Comentarii (2)

Verificați dacă există un director și de a crea, dacă este necesar?

Răspunsul direct la acest lucru este, presupunând o situație simplă în cazul în care nu't aștepta alți utilizatori sau procese să fie încurcați cu directorul dvs.:

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

sau dacă face directorul este supusă unor condiții de rasă (de exemplu, dacă după verificarea există o cale, ceva poate au făcut-o deja) face acest lucru:

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

Dar, probabil, o mai bună abordare este de a se eschiva de resurse dispută problemă, prin utilizarea temporară directoare prin intermediul tempfile:

import tempfile

d = tempfile.mkdtemp()

Aici's esențialul din online doc:

mkdtemp(sufix='', prefix='tmp', dir=None) Utilizator-nevărsat funcția de a crea și să se întoarcă un unic temporar director. Valoarea returnată este cale de director.

directorul este ușor de citit, scriere, și pot fi căutate doar de crearea de utilizator.

Apelantului este responsabil pentru ștergerea director atunci când ați terminat cu ea.

# # # # Noi în Python 3.5: pathlib.Calea " cu " exist_ok

Nu's o nou Cale obiect (ca de 3,4), cu o mulțime de metode ar trebui să fie utilizat cu căi - dintre care unul este mkdir.

(Pentru context, am'm urmărire meu săptămânal rep cu un script. Aici's părțile relevante din codul de script-ul care permite-mi pentru a evita lovirea Stack Overflow mai mult de o dată pe zi pentru aceleași date.)

Prima importurilor relevante:

from pathlib import Path
import tempfile

Am don't trebuie să se ocupe de os.calea.alătură-te acum - doar alături de calea de piese cu un/`:

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

Apoi am idempotently asigura director există - exist_ok argument apare în Python 3.5:

directory.mkdir(exist_ok=True)

Aici's relevante, parte a documentatiei]2:

Dacă exist_ok este adevărat,FileExistsErrorexcepții vor fi ignorate (același comportament caPOSIX mkdir -p` comanda), dar numai dacă ultima componentă cale nu este existent non-director de fișiere.

Aici's un pic mai mult de script - în cazul meu, am'm nu face obiectul unei stări, am doar un proces care se așteaptă ca director (sau fișierele conținute) pentru a fi acolo, și eu nu't au nimic de încercarea de a elimina director.

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

"Cale" obiecte trebuie să fie constrâns să str înainte de alte Api-uri care aștepta str căi le pot folosi.

Poate că Panda ar trebui să fie actualizat pentru a accepta cazuri de clasă abstractă de bază, os.PathLike.

Comentarii (0)

În Python 3.4 puteți utiliza, de asemenea, de brand nou pathlib module:

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.
Comentarii (2)

De relevante Python documentația sugerează utilizarea EAFP stil de codificare (mai Ușor pentru a Cere Iertarea decât Permisiunea). Acest lucru înseamnă că codul

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

este mai bine decât alternativa

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

Documentația sugerează asta exact din cauza stări de discutat în această întrebare. În plus, ca și alții menționează aici, există un avantaj de performanță în interogarea odată, în loc de două ori sistemul de OPERARE. În cele din urmă, argumentul plasate înainte, potențial, în favoarea celui de-al doilea cod în unele cazuri-atunci când dezvoltatorul știe mediului aplicația se execută-poate fi invocată în cazul special în care programul a înființat un mediu privat pentru sine (și alte instanțe ale aceluiași program).

Chiar și în acest caz, aceasta este o practică proastă și poate duce la mult timp inutil de depanare. De exemplu, faptul că ne-am setat permisiunile pentru un director nu ar trebui să ne lase cu impresia permisiunile sunt setate corespunzător pentru scopurile noastre. Un director de mamă ar putea fi montat cu alte permisiuni. În general, un program ar trebui să lucreze întotdeauna în mod corect și programatorul nu trebuie să se aștepte un mediu specific.

Comentarii (0)

În Python3, os.makedirs suporta setarea exist_ok. Setarea implicită este False, care înseamnă o OSError` va fi ridicat în cazul în directorul țintă există deja. Prin setareaexist_okaAdevărat,OSError`` (director există) vor fi ignorate și directorul nu va fi creat.

os.makedirs(path,exist_ok=True)

În Python2, os.makedirs nu't suport setarea exist_ok. Puteți utiliza abordarea din heikki-toivonen's a răspunde:

import os
import errno

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

Puteți utiliza mkpath

# Create a directory and any missing ancestor directories. 
# If the directory already exists, do nothing.

from distutils.dir_util import mkpath
mkpath("test")    

Rețineți că se va crea strămoșul directoare.

Acesta funcționează pentru Python 2 și 3.

Comentarii (2)

Pentru un one-liner soluție, puteți utiliza IPython.utils.path.ensure_dir_exists():

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

De documentația: Ensure că un director există. Dacă nu există, încercați să-l creeze și să protejeze împotriva unei stări dacă un alt proces este de a face același lucru.

Comentarii (3)

Eu folosesc sistem de operare.calea.există()`, aici este un script Python 3, care poate fi folosit pentru a verifica dacă un director există, creați unul dacă nu există, și ștergeți-l dacă există (dacă se dorește).

Se solicită utilizatorilor pentru intrare de director și pot fi ușor modificate.

Comentarii (0)

Puteți utiliza os.listdir pentru asta:

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

Am văzut Heikki Toivonen și a-B-B's răspunsuri și a crezut că de această variație.

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
Comentarii (0)

Am găsit asta Q/O și inițial am fost mirat de unele eșecuri și erori am fost obtinerea. Am de lucru în Python 3 (v. 3.5 într-un Anaconda mediu virtual pe un Arch Linux x86_64 sistem).

Ia în considerare această structură de directoare:

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

Aici sunt experimentele mele/note, care clarifică lucrurile:

# ----------------------------------------------------------------------------
# [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
# ----------------------------------------------------------------------------

Concluzie: în opinia mea, "Metoda 2" este mai robust.

[1] https://stackoverflow.com/questions/273192/how-can-i-create-a-directory-if-it-does-not-exist

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

Comentarii (0)

Dacă se ia în considerare următoarele:

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

înseamnă un director (path) există ȘI este un director. Deci, pentru mine acest drum face ceea ce am nevoie. Deci, eu pot asigurați-vă că acesta este folderul (nu un fișier) și există.

Comentarii (1)