Kaip saugiai sukurti įterptinį katalogą?

Koks elegantiškiausias būdas patikrinti, ar katalogas, į kurį ketinama įrašyti failą, egzistuoja, o jei ne, sukurti katalogą naudojant "Python"? Štai ką bandžiau:

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)

Kažkaip nepastebėjau os.path.exists (ačiū kanja, Blair ir Douglas). Štai ką turiu dabar:

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

Ar yra "open" vėliavėlė, kad tai įvyktų automatiškai?

Sprendimas

Matau du atsakymus su geromis savybėmis ir po nedidelį trūkumą, todėl pateiksiu savo požiūrį:

Išbandykite os.path.exists ir apsvarstykite os.makedirs sukūrimui.

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

Kaip pažymėta komentaruose ir kitur, yra lenktynių sąlyga; jei katalogas sukuriamas tarp os.path.exists ir os.makedirs iškvietimų, os.makedirs nepavyks su OSError. Deja, visuotinis OSError fiksavimas ir tęsimas nėra patikimas, nes bus ignoruojamas nesėkmingas katalogo sukūrimas dėl kitų veiksnių, pavyzdžiui, nepakankamų leidimų, pilno disko ir t. t.

Viena iš galimybių būtų gaudyti OSError ir nagrinėti įterptą klaidos kodą (žr. skyrių Is there there a cross-platform way of getting information from Python's OSError):

import os, errno

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

Arba gali būti antrasis os.path.exists, bet tarkime, kad kitas sukūrė katalogą po pirmojo patikrinimo, o paskui jį pašalino prieš antrąjį – mes vis tiek galime būti apgauti.

Priklausomai nuo taikomosios programos, vienu metu atliekamų operacijų pavojus gali būti didesnis arba mažesnis nei pavojus, kurį kelia kiti veiksniai, pavyzdžiui, failų leidimai. Kūrėjas, prieš pasirinkdamas realizaciją, turėtų daugiau sužinoti apie konkrečią kuriamą taikomąją programą ir numatomą jos aplinką.

Šiuolaikinėse Python versijose šis kodas yra gerokai patobulintas, nes jame atsirado FileExistsError (3.3+ versijoje)...

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

...ir leidžiant raktinį os.makedirs argumentą, vadinamą exist_ok (3.2+ versijoje).

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

Patikrinkite os.makedirs: (Įsitikinama, kad visas kelias egzistuoja.) Kad būtų atsižvelgta į tai, jog katalogas gali egzistuoti, sugaunama OSError. (Jei exist_ok yra False (numatytoji reikšmė), jei tikslinis katalogas jau egzistuoja, iškeliama OSError.)

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

Išbandykite funkciją os.path.exists

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