Vérifier l'existence du répertoire et créer s'il n'existe pas


388

Je me retrouve souvent à écrire des scripts R qui génèrent beaucoup de sortie. Je trouve plus propre de mettre cette sortie dans ses propres répertoires. Ce que j'ai écrit ci-dessous vérifiera l'existence d'un répertoire et s'y déplacera, ou créera le répertoire puis se déplacera dans celui-ci. Y a-t-il une meilleure façon d'aborder cela?

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
Je suis sûr que j'ai vu une fonction R qui crée un répertoire temporaire avec un nom généré aléatoirement et renvoie le nom. Je pense qu'il y en a un similaire qui crée un fichier temporaire. Je ne peux pas les trouver spontanément, mais le paquet Databel ( cran.r-project.org/web/packages/DatABEL/index.html ) a une fonction get_temporary_file_name.
PaulHurleyuk

42
Vous ne devriez jamais utiliser setwd()dans le code R - il défait fondamentalement l'idée d'utiliser un répertoire de travail car vous ne pouvez plus facilement déplacer votre code entre les ordinateurs.
hadley

6
@hadley sujet intéressant à méditer, j'apprécierais vos réflexions sur d'autres méthodes dans le même but. Au travail, tous les ordinateurs sont synchronisés sur le même réseau afin que les chemins de fichiers soient cohérents. S'ils ne le sont pas, nous avons plus de problèmes à régler que la portabilité d'un script. Dans cet exemple particulier, j'écrivais un script qui serait chargé sur une machine qui sera transportée dans nos parcs nationaux pendant 2 ans. Ce script récupérera les données d'une instance SQL locale, effectuera un traitement et crachera un .csv. Le produit final sera un .batfichier que l'utilisateur final n'aura jamais à modifier.
Chase

@Chase Mais vous n'avez pas besoin setwdde travailler avec des chemins réseau. Il vous suffit de fournir des chemins pour enregistrer les résultats et de continuer à travailler avec le chemin actuel (celui établi au démarrage de la session R). Ou commencez R avec le répertoire de travail de désir.
Marek

5
Oui. Ou paramétrez out_dir <- "path/to/output/directory"puis utilisez write.table(file = file.path(out_dir,"table_1.csv"), ...). Ou même out_file <- function(fnm) file.path("path/to/output/directory", fnm)et ensuite write.table(file = out_file("table_1.csv"), ...)(méthode similaire que j'utilise lorsque je travaille avec des lecteurs réseau).
Marek

Réponses:


403

Utilisation showWarnings = FALSE:

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

dir.create()ne plante pas si le répertoire existe déjà, il affiche simplement un avertissement. Donc, si vous pouvez vivre en voyant des avertissements, il n'y a aucun problème à simplement faire ceci:

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

58
Soyez conscient lors de l'utilisation showWarnings = FALSEque cela masquera également d'autres avertissements tels que le répertoire étant incréable.
zelanix

5
^ Existe-t-il un moyen de supprimer uniquement un avertissement spécifique?
Bas

2
Salut, je veux ot créer un répertoire imbriqué, comme si je suis dans le dossier test1 puis à l'intérieur de test2 à l'intérieur de test3 ... mais en ce moment je suis confronté à un problème. Existe-t-il un moyen de créer 3 niveaux de répertoire même si directory1 ne se ferme pas ??
Praveen Kesani

10
@PraveenKesani Est - ce que vous cherchez: dir.create("test1/test2/test3/", recursive=TRUE)?
doyen.

6
@Bas Réponse très tardive mais suppressWarnings(<statement>)supprimera les avertissements pour cette seule déclaration.
Ram RS

163

Depuis le 16 avril 2015, avec la sortie de R 3.2.0, une nouvelle fonction est appelée dir.exists(). Pour utiliser cette fonction et créer le répertoire s'il n'existe pas, vous pouvez utiliser:

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

Cela retournera FALSEsi le répertoire existe déjà ou est incréable, et TRUEs'il n'existait pas mais a été créé avec succès.

Notez que pour vérifier simplement si le répertoire existe, vous pouvez utiliser

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

9
Juste pour noter que ce n'est pas une bonne pratique à utiliser ifelse()pour les branchements non vectorisés.
Lionel Henry

2
@Bas car votre code se lit faussement comme si quelque chose de vectorisé se passait. C'est comme utiliser vectorisé |au lieu de scalaire ||. Cela fonctionne mais c'est une mauvaise pratique.
Lionel Henry

1
Oh putain, j'ai donc fait mes déclarations if également en utilisant |, la vectorisation est-elle la raison pour laquelle cela ne fonctionne pas ||parfois? Je sais que c'est hors sujet mais je suis trop impatient de le découvrir. Je vais sans aucun doute en savoir plus sur la vectorisation. Merci
Bas

4
Alors, quelle est la meilleure façon de procéder si nous évitons ifelse?
KillerSnail

6
en utilisant if et else;)
Lionel Henry

17

En termes d'architecture générale, je recommanderais la structure suivante en ce qui concerne la création de répertoires. Cela couvrira la plupart des problèmes potentiels et tout autre problème de création de répertoire sera détecté par l' dir.createappel.

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
}

Sachez également que s'il ~/foon'existe pas, un appel à dir.create('~/foo/bar')échouera, sauf si vous le spécifiez recursive = TRUE.


3
y a-t-il une raison pour laquelle vous utilisez coller (...) vs file.path (mainDir, subDir). De plus, si vous avez fait un chemin <- file.path (mainDir, subDir), vous pouvez le réutiliser 5 fois pour rendre les instructions if plus lisibles.
MikeF

15

Voici la vérification des simples , et crée le répertoire si n'existe pas:

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

L'utilisation de file.exists () pour tester l'existence du répertoire est un problème dans la publication d'origine. Si subDir incluait le nom d'un fichier existant (plutôt qu'un simple chemin), file.exists () retournerait TRUE, mais l'appel à setwd () échouerait car vous ne pouvez pas définir le répertoire de travail pour pointer vers un fichier.

Je recommanderais l'utilisation de file_test (op = "- d", subDir), qui retournera "TRUE" si subDir est un répertoire existant, mais FALSE si subDir est un fichier existant ou un fichier ou répertoire inexistant. De même, la vérification d'un fichier peut être effectuée avec op = "- f".

De plus, comme décrit dans un autre commentaire, le répertoire de travail fait partie de l'environnement R et doit être contrôlé par l'utilisateur et non par un script. Idéalement, les scripts ne devraient pas modifier l'environnement R. Pour résoudre ce problème, je pourrais utiliser options () pour stocker un répertoire globalement disponible où je voulais toute ma sortie.

Considérez donc la solution suivante, où someUniqueTag n'est qu'un préfixe défini par le programmeur pour le nom de l'option, ce qui rend peu probable qu'une option portant le même nom existe déjà. (Par exemple, si vous développez un package appelé "filer", vous pouvez utiliser filer.mainDir et filer.subDir).

Le code suivant serait utilisé pour définir les options disponibles pour une utilisation ultérieure dans d'autres scripts (évitant ainsi l'utilisation de setwd () dans un script) et pour créer le dossier si nécessaire:

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

Ensuite, dans tout script ultérieur qui devait manipuler un fichier dans subDir, vous pourriez utiliser quelque chose comme:

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

Cette solution laisse le répertoire de travail sous le contrôle de l'utilisateur.


8

J'ai eu un problème avec R 2.15.3 où en essayant de créer une arborescence récursivement sur un lecteur réseau partagé, j'obtiendrais une erreur d'autorisation.

Pour contourner cette bizarrerie, je crée manuellement la structure;

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

mkdirs("H:/foo/bar")

5

Bon mot:

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

Exemple:

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

2

Pour savoir si un chemin est un répertoire valide, essayez:

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

file.info ne se soucie pas d'une barre oblique à la fin.

file.existssous Windows échouera pour un répertoire s'il se termine par une barre oblique et réussit sans lui. Cela ne peut donc pas être utilisé pour déterminer si un chemin est un répertoire.

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'est-ce qui ne va pas dans cette réponse (en plus de ne pas inclure la dir.create()partie)? Les déclarations sont-elles erronées ou simplement jugées inutiles pour résoudre la question en question?
mschilli
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.