¿Cuál es la forma más elegante de verificar si el directorio en el que se va a escribir un archivo existe y, de no ser así, crear el directorio usando Python? Esto es lo que probé:

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)

De alguna manera, me perdí os.path.exists(gracias kanja, Blair y Douglas). Esto es lo que tengo ahora:

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

¿Hay una bandera para open(), que hace que esto suceda automáticamente?

respuesta

En Python ≥ 3.5, use pathlib.Path.mkdir:

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

Para versiones anteriores de Python, veo dos respuestas con buenas cualidades, cada una con un pequeño defecto, así que daré mi opinión:

Pruebe os.path.existsy considere os.makedirspara la creación.

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

Como se señaló en los comentarios y en otros lugares, hay una condición de carrera: si el directorio se crea entre os.path.existsy las os.makedirsllamadas, os.makedirsfallará con un OSError. Desafortunadamente, la captura general OSErrory la continuación no son infalibles, ya que ignorarán una falla al crear el directorio debido a otros factores, como permisos insuficientes, disco lleno, etc.

Una opción sería atrapar OSErrory examinar el código de error incrustado (consulte ¿Existe una forma multiplataforma de obtener información del OSError de Python ):

import os, errno

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

Alternativamente, podría haber un segundo os.path.exists, pero supongamos que otro creó el directorio después de la primera verificación y luego lo eliminó antes de la segunda; aún podríamos ser engañados.

Dependiendo de la aplicación, el peligro de las operaciones simultáneas puede ser mayor o menor que el peligro que representan otros factores, como los permisos de archivos. El desarrollador tendría que saber más sobre la aplicación en particular que se está desarrollando y su entorno esperado antes de elegir una implementación.

Las versiones modernas de Python mejoran bastante este código, tanto exponiendo FileExistsError(en 3.3+)...

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

... y al permitir que se llame un argumento de palabra claveos.makedirsexist_ok (en 3.2+).

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

Pitón 3.5+:

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

pathlib.Path.mkdircomo se usó anteriormente, crea recursivamente el directorio y no genera una excepción si el directorio ya existe. Si no necesita o no desea que se creen los padres, omita el parentsargumento.

Pitón 3.2+:

usando pathlib:

Si puede, instale el pathlibbackport actual llamado pathlib2. No instale el backport antiguo sin mantenimiento llamado pathlib. A continuación, consulte la sección Python 3.5+ anterior y utilícelo de la misma manera.

Si usa Python 3.4, aunque viene con , le falta la opción pathlibútil . exist_okEl backport está destinado a ofrecer una implementación más nueva y superior mkdirque incluye esta opción que falta.

usando os:

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

os.makedirscomo se usó anteriormente, crea recursivamente el directorio y no genera una excepción si el directorio ya existe. Tiene el exist_okargumento opcional solo si usa Python 3.2+, con un valor predeterminado de False. Este argumento no existe en Python 2.x hasta 2.7. Como tal, no hay necesidad de manejo manual de excepciones como con Python 2.7.

Pitón 2.7+:

usando pathlib:

Si puede, instale el pathlibbackport actual llamado pathlib2. No instale el backport antiguo sin mantenimiento llamado pathlib. A continuación, consulte la sección Python 3.5+ anterior y utilícelo de la misma manera.

usando os:

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

Si bien una solución ingenua puede usar primero os.path.isdirseguido de os.makedirs, la solución anterior invierte el orden de las dos operaciones. Al hacerlo, evita una condición de carrera común que tiene que ver con un intento duplicado de crear el directorio y también elimina la ambigüedad de los archivos de los directorios.

Tenga en cuenta que capturar la excepción y usarla errnotiene una utilidad limitada porque OSError: [Errno 17] File exists, es decir errno.EEXIST, se genera tanto para archivos como para directorios. Es más confiable simplemente verificar si el directorio existe.

Alternativa:

mkpathcrea el directorio anidado y no hace nada si el directorio ya existe. Esto funciona tanto en Python 2 como en 3.

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

Según el error 10948 , una limitación grave de esta alternativa es que solo funciona una vez por proceso de Python para una ruta determinada. En otras palabras, si lo usa para crear un directorio, luego elimine el directorio desde dentro o fuera de Python, luego utilícelo mkpathnuevamente para recrear el mismo directorio, mkpathsimplemente usará silenciosamente su información almacenada en caché no válida de haber creado previamente el directorio, y no lo hará. en realidad hacer el directorio de nuevo. Por el contrario, os.makedirsno se basa en ningún caché de este tipo. Esta limitación puede estar bien para algunas aplicaciones.


Con respecto al modo del directorio , consulte la documentación si le interesa.

Usar try except y el código de error correcto del módulo errno elimina la condición de carrera y es multiplataforma:

import os
import errno

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

En otras palabras, intentamos crear los directorios, pero si ya existen ignoramos el error. Por otro lado, se informa cualquier otro error. Por ejemplo, si crea el directorio 'a' de antemano y le quita todos los permisos, obtendrá un OSErroraumento con errno.EACCES(Permiso denegado, error 13).

A partir de Python 3.5, pathlib.Path.mkdirtiene una exist_okbandera:

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

Esto crea recursivamente el directorio y no genera una excepción si el directorio ya existe.

(al igual que os.makedirsobtuvo una exist_okbandera a partir de python 3.2, por ejemplo os.makedirs(path, exist_ok=True))


Nota: cuando publiqué esta respuesta, ninguna de las otras respuestas mencionó exist_ok...

Personalmente, recomendaría que use os.path.isdir()para probar en lugar de os.path.exists().

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

Si usted tiene:

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

Y una entrada de usuario tonta:

:: /tmp/dirname/filename.etc

... Terminará con un directorio llamado filename.etccuando pase ese argumento os.makedirs()si prueba con os.path.exists().

Verifique os.makedirs: (Se asegura de que exista la ruta completa).
Para manejar el hecho de que el directorio podría existir, capture OSError. (Si exist_okes False(el valor predeterminado), OSErrorse genera un si el directorio de destino ya existe).

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

Prueba la os.path.existsfunción

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

Información sobre los detalles de esta situación

Da un archivo en particular en una ruta determinada y extrae el directorio de la ruta del archivo. Luego, después de asegurarse de que tiene el directorio, intenta abrir un archivo para leerlo. Para comentar este código:

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

Queremos evitar sobrescribir la función incorporada, dir. Además, filepatho tal vez fullfilepathsea probablemente un mejor nombre semántico que filename, por lo que sería mejor escribirlo:

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

Su objetivo final es abrir este archivo, inicialmente declaró, para escribir, pero esencialmente se está acercando a este objetivo (basado en su código) de esta manera, que abre el archivo para lectura :

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

Asumiendo apertura para lectura

¿Por qué crearía un directorio para un archivo que espera que esté allí y pueda leer?

Simplemente intente abrir el archivo.

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

Si el directorio o archivo no está allí, obtendrá un IOErrornúmero de error asociado: errno.ENOENTseñalará el número de error correcto independientemente de su plataforma. Puedes atraparlo si quieres, por ejemplo:

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

Asumiendo que estamos abriendo para escribir

Esto es probablemente lo que estás deseando.

En este caso, probablemente no nos enfrentemos a ninguna condición de carrera. Así que haz lo que estabas, pero ten en cuenta que para escribir, debes abrir con el wmodo (o aagregar). También es una buena práctica de Python usar el administrador de contexto para abrir archivos.

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

Sin embargo, digamos que tenemos varios procesos de Python que intentan poner todos sus datos en el mismo directorio. Entonces podemos tener disputas sobre la creación del directorio. En ese caso, es mejor envolver la makedirsllamada en un bloque try-except.

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)

He puesto lo siguiente. Sin embargo, no es totalmente infalible.

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

Ahora, como digo, esto no es realmente infalible, porque tenemos la posibilidad de fallar al crear el directorio y otro proceso de creación durante ese período.

Check if a directory exists and create it if necessary?

La respuesta directa a esto es, suponiendo una situación simple en la que no espera que otros usuarios o procesos interfieran con su directorio:

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

o si la creación del directorio está sujeta a condiciones de carrera (es decir, si después de verificar que existe la ruta, es posible que otra persona ya la haya creado), haga lo siguiente:

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

Pero quizás un enfoque aún mejor es eludir el problema de la contención de recursos, mediante el uso de directorios temporales a través de tempfile:

import tempfile

d = tempfile.mkdtemp()

Aquí está lo esencial del documento en línea:

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.

Nuevo en Python 3.5: pathlib.Pathconexist_ok

Hay un nuevo Pathobjeto (a partir de 3.4) con muchos métodos que uno querría usar con rutas, uno de los cuales es mkdir.

(Para el contexto, estoy rastreando mi representante semanal con un script. Aquí están las partes relevantes del código del script que me permiten evitar presionar Stack Overflow más de una vez al día para obtener los mismos datos).

Primero las importaciones relevantes:

from pathlib import Path
import tempfile

No tenemos que lidiar con eso os.path.joinahora, solo une las partes de la ruta con un /:

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

Luego me aseguro de forma idempotente de que el directorio existe; el exist_okargumento aparece en Python 3.5:

directory.mkdir(exist_ok=True)

Aquí está la parte relevante de la documentación :

If exist_ok is true, FileExistsError exceptions will be ignored (same behavior as the POSIX mkdir -p command), but only if the last path component is not an existing non-directory file.

Aquí hay un poco más de la secuencia de comandos: en mi caso, no estoy sujeto a una condición de carrera, solo tengo un proceso que espera que el directorio (o los archivos contenidos) estén allí, y no tengo nada tratando de eliminar El directorio.

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

Pathlos objetos deben ser forzados strantes de que otras API que esperan strrutas puedan usarlos.

Quizás Pandas debería actualizarse para aceptar instancias de la clase base abstracta, os.PathLike.

En Python 3.4 también puede usar el nuevo pathlibmódulo :

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.

Para una solución de una sola línea, puede usar IPython.utils.path.ensure_dir_exists():

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

De la documentación : asegúrese de que exista un directorio. Si no existe, intente crearlo y protéjase contra una condición de carrera si otro proceso está haciendo lo mismo.

IPython es un paquete de extensión, no forma parte de la biblioteca estándar.

En Python3 , os.makedirsadmite la configuración exist_ok. La configuración predeterminada es False, lo que significa que OSErrorse generará un si el directorio de destino ya existe. Si se establece exist_oken True, OSError(el directorio existe) se ignorará y no se creará el directorio.

os.makedirs(path,exist_ok=True)

En Python2 , os.makedirsno es compatible con la configuración exist_ok. Puede usar el enfoque en la respuesta de heikki-toivonen :

import os
import errno

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

La documentación relevante de Python sugiere el uso del estilo de codificación EAFP (Más fácil de pedir perdón que permiso) . Esto significa que el código

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

es mejor que la alternativa

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

La documentación sugiere esto exactamente debido a la condición de carrera discutida en esta pregunta. Además, como otros mencionan aquí, existe una ventaja de rendimiento al consultar una vez en lugar de dos veces el sistema operativo. Finalmente, el argumento presentado, potencialmente, a favor del segundo código en algunos casos, cuando el desarrollador conoce el entorno en el que se ejecuta la aplicación, solo puede defenderse en el caso especial de que el programa haya configurado un entorno privado para mismo (y otras instancias del mismo programa).

Incluso en ese caso, esta es una mala práctica y puede conducir a una depuración inútil durante mucho tiempo. Por ejemplo, el hecho de que establezcamos los permisos para un directorio no debería dejarnos con la impresión de que los permisos están establecidos de manera adecuada para nuestros propósitos. Se podría montar un directorio principal con otros permisos. En general, un programa siempre debe funcionar correctamente y el programador no debe esperar un entorno específico.

Encontré esta pregunta y respuesta después de que me desconcertaron algunas de las fallas y errores que recibía mientras trabajaba con directorios en Python. Estoy trabajando en Python 3 (v.3.5 en un entorno virtual Anaconda en un sistema Arch Linux x86_64).

Considere esta estructura de directorio:

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

Aquí están mis experimentos/notas, que proporcionan aclaración:

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

Conclusión: en mi opinión, el "Método 2" es más robusto.

[1] ¿Cómo puedo crear un directorio anidado de forma segura?

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

Puedes usarmkpath

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

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

Tenga en cuenta que también creará los directorios de antepasados.

Funciona para Python 2 y 3.

Yo uso os.path.exists(), aquí hay un script de Python 3 que se puede usar para verificar si existe un directorio, crear uno si no existe y eliminarlo si existe (si lo desea).

Solicita a los usuarios que ingresen el directorio y se puede modificar fácilmente.

¿Por qué no usar el módulo de subproceso si se ejecuta en una máquina que admite el comando mkdircon la -popción? Funciona en python 2.7 y python 3.6

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

Debería hacer el truco en la mayoría de los sistemas.

En situaciones en las que la portabilidad no importa (por ejemplo, usar Docker), la solución es 2 líneas limpias. Tampoco tiene que agregar lógica para verificar si existen directorios o no. Finalmente, es seguro volver a ejecutar sin efectos secundarios.

Si necesita manejo de errores:

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

Debe establecer la ruta completa antes de crear el directorio:

import os,sys,inspect
import pathlib

currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
your_folder = currentdir + "/" + "your_folder"

if not os.path.exists(your_folder):
   pathlib.Path(your_folder).mkdir(parents=True, exist_ok=True)

Esto funciona para mí y, con suerte, también funcionará para usted.

En caso de que esté escribiendo un archivo en una ruta variable, puede usar esto en la ruta del archivo para asegurarse de que se creen los directorios principales.

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)

Funciona incluso si path_to_filees file.ext(cero directorios de profundidad).

Consulte pathlib.PurePath.parent y pathlib.Path.mkdir .

Vi las respuestas de Heikki Toivonen y ABB y pensé en esta variación.

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

Utilice este comando comprobar y crear dir

 if not os.path.isdir(test_img_dir):
     os.mkdir(test_img_dir)

Llame a la función create_dir()en el punto de entrada de su programa/proyecto.

import os

def create_dir(directory):
    if not os.path.exists(directory):
        print('Creating Directory '+directory)
        os.makedirs(directory)

create_dir('Project directory')

Puedes usar os.listdirpara esto:

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

Si consideras lo siguiente:

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

significa que existe un directorio (ruta) Y es un directorio. Así que para mí de esta manera hace lo que necesito. Entonces puedo asegurarme de que sea una carpeta (no un archivo) y que exista.

Esto puede no responder exactamente a la pregunta. Pero supongo que su verdadera intención es crear un archivo y sus directorios principales, dado su contenido, todo en 1 comando.

Puedes hacer eso con la fastcoreextensión a pathlib:path.mk_write(data)

from fastcore.utils import Path
Path('/dir/to/file.txt').mk_write('Hello World')

Ver más en la documentación de fastcore

La mejor manera de hacer esto en Python

#Devil
import os
directory = "./out_dir/subdir1/subdir2"
if not os.path.exists(directory):
    os.makedirs(directory)

La forma más rápida y segura de hacerlo es: creará si no existe y omitirá si existe:

from pathlib import Path
Path("path/with/childs/.../").mkdir(parents=True, exist_ok=True)
import os
if os.path.isfile(filename):
    print "file exists"
else:
    "Your code here"

Where your code here is use the (touch) command

Esto verificará si el archivo está allí; si no lo está, lo creará.

Bajo Linux puede crear directorios anidados

 dir1/dir2/... 

en una línea:

import os
os.system("mkdir -p {0}".format('dir1/dir2/dir3'))