¿Cómo creo un directorio y los directorios principales que faltan?
¿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/directory
hace esto.
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.exists
y consideralo os.makedirs
para 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.exists
y os.makedirs
, os.makedirs
fallará con un archivo OSError
. Desafortunadamente, la captura general OSError
y 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 OSError
y 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.makedirs
exist_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.mkdir
como 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 parents
argumento.
Pitón 3.2+:
Usando pathlib
:
Si puede, instale el pathlib
backport 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_ok
opción útil. El backport está destinado a ofrecer una implementación más nueva y superior que mkdir
incluye esta opción faltante.
Usando os
:
import os
os.makedirs(path, exist_ok=True)
os.makedirs
como se usó anteriormente crea recursivamente el directorio y no genera una excepción si el directorio ya existe. Tiene el exist_ok
argumento 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 pathlib
backport 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.isdir
seguido 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 errno
tiene 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:
mkpath
crea 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 distutils
ha 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 mkpath
nuevamente para recrear el mismo directorio, mkpath
simplemente 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.makedirs
no 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.
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 OSError
mensaje con errno.EACCES
(Permiso denegado, error 13).