Verifique la existencia del directorio y cree si no existe


388

A menudo me encuentro escribiendo scripts R que generan una gran cantidad de resultados. Me parece más limpio poner esta salida en su propio directorio (s). Lo que he escrito a continuación verificará la existencia de un directorio y se moverá a él, o creará el directorio y luego se moverá a él. ¿Hay una mejor manera de abordar esto?

mainDir <- "c:/path/to/main/dir"
subDir <- "outputDirectory"

if (file.exists(subDir)){
    setwd(file.path(mainDir, subDir))
} else {
    dir.create(file.path(mainDir, subDir))
    setwd(file.path(mainDir, subDir))

}

1
Estoy seguro de que he visto una función R que crea un directorio temporal con un nombre generado aleatoriamente y devuelve el nombre. Creo que hay uno similar que crea un archivo temporal. No puedo encontrarlos de forma informal, pero el paquete Databel ( cran.r-project.org/web/packages/DatABEL/index.html ) tiene una función get_temporary_file_name.
PaulHurleyuk

42
Nunca debe usar setwd()en el código R, básicamente elimina la idea de usar un directorio de trabajo porque ya no puede mover fácilmente su código entre computadoras.
hadley

66
@hadley tema interesante para reflexionar, agradecería sus pensamientos sobre otros métodos para el mismo fin. En el trabajo, todas las computadoras se sincronizan con la misma red, por lo que las rutas de los archivos son consistentes. Si no lo son, tenemos problemas más importantes que tratar que la portabilidad de un script. En este ejemplo en particular, estaba escribiendo un guión que se cargaría en una máquina que se transportará por nuestros parques nacionales durante 2 años. Este script tomará datos de una instancia local de SQL, procesará un poco y escupirá un .csv. El producto final será un .batarchivo que el usuario final nunca tendrá que modificar.
Chase

@Chase Pero no necesita setwdtrabajar con rutas de red. Solo necesita proporcionar rutas para guardar resultados y seguir trabajando con la ruta actual (aquella que se estableció cuando se inició la sesión R). O comience R con el directorio de trabajo deseado.
Marek

55
Sí. O parametrizar out_dir <- "path/to/output/directory"y luego usar write.table(file = file.path(out_dir,"table_1.csv"), ...). O incluso out_file <- function(fnm) file.path("path/to/output/directory", fnm)y luego write.table(file = out_file("table_1.csv"), ...)(método similar que uso cuando trabajo con unidades de red).
Marek

Respuestas:


403

Uso showWarnings = FALSE:

dir.create(file.path(mainDir, subDir), showWarnings = FALSE)
setwd(file.path(mainDir, subDir))

dir.create()no se bloquea si el directorio ya existe, solo imprime una advertencia. Entonces, si puede vivir viendo advertencias, no hay problema con solo hacer esto:

dir.create(file.path(mainDir, subDir))
setwd(file.path(mainDir, subDir))

58
Tenga en cuenta al usar showWarnings = FALSEque esto también ocultará otras advertencias, como que el directorio no se pueda crear.
zelanix

55
^ ¿Hay alguna manera de suprimir solo una advertencia específica?
Bas

2
Hola, no quiero crear un directorio anidado, como si estuviera en la carpeta prueba1 y luego dentro de la prueba2 dentro de la prueba3 ... pero ahora estoy enfrentando un problema. ¿Hay alguna manera de que pueda crear 3 niveles de directorio incluso si el directorio1 no sale?
Praveen Kesani

10
@PraveenKesani ¿Es esto lo que estás buscando dir.create("test1/test2/test3/", recursive=TRUE)?
decano.

66
@Bas Respuesta realmente tardía pero suppressWarnings(<statement>)suprimirá las advertencias solo por esa declaración.
Ram RS

163

A partir del 16 de abril de 2015, con el lanzamiento de R 3.2.0hay una nueva función llamada dir.exists(). Para usar esta función y crear el directorio si no existe, puede usar:

ifelse(!dir.exists(file.path(mainDir, subDir)), dir.create(file.path(mainDir, subDir)), FALSE)

Esto devolverá FALSEsi el directorio ya existe o no es creíble, y TRUEsi no existía pero se creó con éxito.

Tenga en cuenta que para verificar simplemente si el directorio existe, puede usar

dir.exists(file.path(mainDir, subDir))

99
Solo para tener en cuenta que no es una buena práctica usar ifelse()para ramificaciones no vectorizadas.
Lionel Henry el

2
@Bas porque su código lee falsamente como si algo vectorizado estuviera sucediendo. Es como usar vectorizado en |lugar de escalar ||. Funciona pero es una mala práctica.
Lionel Henry

1
Oh, maldición, así que he estado haciendo mis declaraciones if mal también al usarlas |, ¿es la vectorización la razón por la que a veces no funciona ||? Sé que esto está fuera de tema, pero estoy demasiado ansioso por descubrirlo. Definitivamente iré y leeré más sobre vectorización. Gracias
Bas

44
Entonces, ¿cuál es la mejor forma de hacer esto si debemos evitarlo ifelse?
KillerSnail

66
usando if y else;)
Lionel Henry

17

En términos de arquitectura general, recomendaría la siguiente estructura con respecto a la creación de directorios. Esto cubrirá la mayoría de los problemas potenciales y la dir.createllamada detectará cualquier otro problema con la creación del directorio .

mainDir <- "~"
subDir <- "outputDirectory"

if (file.exists(paste(mainDir, subDir, "/", sep = "/", collapse = "/"))) {
    cat("subDir exists in mainDir and is a directory")
} else if (file.exists(paste(mainDir, subDir, sep = "/", collapse = "/"))) {
    cat("subDir exists in mainDir but is a file")
    # you will probably want to handle this separately
} else {
    cat("subDir does not exist in mainDir - creating")
    dir.create(file.path(mainDir, subDir))
}

if (file.exists(paste(mainDir, subDir, "/", sep = "/", collapse = "/"))) {
    # By this point, the directory either existed or has been successfully created
    setwd(file.path(mainDir, subDir))
} else {
    cat("subDir does not exist")
    # Handle this error as appropriate
}

También tenga en cuenta que si ~/foono existe, la llamada a dir.create('~/foo/bar')fallará a menos que usted especifique recursive = TRUE.


3
¿hay alguna razón por la que use pegar (...) vs file.path (mainDir, subDir)? Además, si hiciste una ruta <- file.path (mainDir, subDir), podrías reutilizarla 5 veces para que las declaraciones if sean más legibles.
MikeF

14

Aquí está la verificación simple , y crea el directorio si no existe:

## Provide the dir name(i.e sub dir) that you want to create under main dir:
output_dir <- file.path(main_dir, sub_dir)

if (!dir.exists(output_dir)){
dir.create(output_dir)
} else {
    print("Dir already exists!")
}

9

El uso de file.exists () para probar la existencia del directorio es un problema en la publicación original. Si subDir incluye el nombre de un archivo existente (en lugar de solo una ruta), file.exists () devolvería VERDADERO, pero la llamada a setwd () fallaría porque no puede configurar el directorio de trabajo para que apunte a un archivo.

Recomendaría el uso de file_test (op = "- d", subDir), que devolverá "TRUE" si subDir es un directorio existente, pero FALSO si subDir es un archivo existente o un archivo o directorio inexistente. Del mismo modo, la comprobación de un archivo se puede lograr con op = "- f".

Además, como se describe en otro comentario, el directorio de trabajo es parte del entorno R y debe ser controlado por el usuario, no por un script. Los scripts deberían, idealmente, no cambiar el entorno R. Para solucionar este problema, podría usar options () para almacenar un directorio disponible globalmente donde quisiera toda mi salida.

Entonces, considere la siguiente solución, donde someUniqueTag es solo un prefijo definido por el programador para el nombre de la opción, lo que hace improbable que ya exista una opción con el mismo nombre. (Por ejemplo, si estaba desarrollando un paquete llamado "filer", podría usar filer.mainDir y filer.subDir).

El siguiente código se usaría para establecer opciones que están disponibles para su uso posterior en otros scripts (evitando así el uso de setwd () en un script), y para crear la carpeta si es necesario:

mainDir = "c:/path/to/main/dir"
subDir = "outputDirectory"

options(someUniqueTag.mainDir = mainDir)
options(someUniqueTag.subDir = "subDir")

if (!file_test("-d", file.path(mainDir, subDir)){
  if(file_test("-f", file.path(mainDir, subDir)) {
    stop("Path can't be created because a file with that name already exists.")
  } else {
    dir.create(file.path(mainDir, subDir))
  }
}

Luego, en cualquier script posterior que necesite manipular un archivo en subDir, puede usar algo como:

mainDir = getOption(someUniqueTag.mainDir)
subDir = getOption(someUniqueTag.subDir)
filename = "fileToBeCreated.txt"
file.create(file.path(mainDir, subDir, filename))

Esta solución deja el directorio de trabajo bajo el control del usuario.


8

Tuve un problema con R 2.15.3 por el cual al intentar crear una estructura de árbol de forma recursiva en una unidad de red compartida recibía un error de permiso.

Para evitar esta rareza, creo manualmente la estructura;

mkdirs <- function(fp) {
    if(!file.exists(fp)) {
        mkdirs(dirname(fp))
        dir.create(fp)
    }
} 

mkdirs("H:/foo/bar")

5

Un trazador de líneas:

if (!dir.exists(output_dir)) {dir.create(output_dir)}

Ejemplo:

dateDIR <- as.character(Sys.Date())
outputDIR <- file.path(outD, dateDIR)
if (!dir.exists(outputDIR)) {dir.create(outputDIR)}

2

Para averiguar si una ruta es un directorio válido, intente:

file.info(cacheDir)[1,"isdir"]

file.info no le importa una barra al final.

file.existsen Windows fallará para un directorio si termina en una barra diagonal y tiene éxito sin él. Por lo tanto, esto no se puede usar para determinar si una ruta es un directorio.

file.exists("R:/data/CCAM/CCAMC160b_echam5_A2-ct-uf.-5t05N.190to240E_level1000/cache/")
[1] FALSE

file.exists("R:/data/CCAM/CCAMC160b_echam5_A2-ct-uf.-5t05N.190to240E_level1000/cache")
[1] TRUE

file.info(cacheDir)["isdir"]

¿Qué tiene de malo esta respuesta (aparte de no incluir la dir.create()parte)? ¿Las afirmaciones son incorrectas o simplemente no se consideran útiles para resolver la pregunta en cuestión?
mschilli
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.