¿Cómo creo un directorio y los directorios principales que faltan?

Resuelto Parand asked hace 16 años • 27 respuestas

¿Cómo creo un directorio en una ruta determinada y también creo los directorios principales que faltan a lo largo de esa ruta? Por ejemplo, el comando Bash mkdir -p /path/to/nested/directoryhace esto.

Parand avatar Nov 08 '08 01:11 Parand
Aceptado

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 al respecto:

Pruébalo os.path.existsy consideralo 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, existe una condición de carrera: si el directorio se crea entre las llamadas os.path.existsy os.makedirs, os.makedirsfallará con un archivo OSError. Desafortunadamente, la captura general OSErrory la continuación no son infalibles, ya que ignorará un error 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 de 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 así podríamos dejarnos engañar.

Dependiendo de la aplicación, el peligro de las operaciones simultáneas puede ser mayor o menor que el peligro que plantean otros factores, como los permisos de archivos. El desarrollador tendría que saber más sobre la aplicación 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 al exponer FileExistsError(en 3.3+)...

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

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

os.makedirs("path/to/directory", exist_ok=True)  # succeeds even if directory exists.
Blair Conrad avatar Nov 07 '2008 19:11 Blair Conrad

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 antiguo backport no mantenido llamado pathlib. A continuación, consulte la sección Python 3.5+ anterior y utilícela de la misma manera.

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

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 se 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 ocurre con Python 2.7.

Pitón 2.7+:

Usando pathlib:

Si puede, instale el pathlibbackport actual llamado pathlib2. No instale el antiguo backport no mantenido llamado pathlib. A continuación, consulte la sección Python 3.5+ anterior y utilícela 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 Python 3. Sin embargo, tenga en cuenta que distutilsha quedado obsoleto y que su eliminación está programada para Python 3.12.

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

Según el error 10948 , una grave limitación de esta alternativa es que funciona solo una vez por proceso de Python para una ruta determinada. En otras palabras, si lo usa para crear un directorio, luego elimina el directorio desde dentro o fuera de Python, luego lo usa 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 De hecho, vuelva a crear el directorio. Por el contrario, os.makedirsno depende de dicho caché. Esta limitación puede estar bien para algunas aplicaciones.


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

Asclepius avatar Jan 16 '2013 17:01 Asclepius

El uso de 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

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

Heikki Toivonen avatar Feb 17 '2011 17:02 Heikki Toivonen