Verifique a existência do diretório e crie se não existir


388

Costumo me escrever scripts R que geram muita saída. Acho mais limpo colocar essa saída em seu próprio diretório (s). O que eu escrevi abaixo verificará a existência de um diretório e será movido para ele, ou criará o diretório e depois será movido para ele. Existe uma maneira melhor de abordar isso?

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

}

11
Tenho certeza de que vi uma função R que cria um diretório temporário com um nome gerado aleatoriamente e retorna o nome. Eu acho que há um semelhante que cria um arquivo temporário. Não consigo encontrá-los de imediato, mas o pacote Databel ( cran.r-project.org/web/packages/DatABEL/index.html ) tem a função get_temporary_file_name.
PaulHurleyuk

42
Você nunca deve usar o setwd()código R - basicamente derrota a idéia de usar um diretório ativo porque não é mais possível mover seu código facilmente entre computadores.
quer

6
@ Hadley tópico interessante para refletir, eu apreciaria seus pensamentos sobre outros métodos para o mesmo fim. No trabalho, todos os computadores são sincronizados com a mesma rede, para que os caminhos dos arquivos sejam consistentes. Caso contrário, temos problemas maiores para lidar do que a portabilidade de um script. Neste exemplo em particular, eu estava escrevendo um script que seria carregado em uma máquina que será transportada pelos nossos parques nacionais por 2 anos. Este script irá coletar dados de uma instância SQL local, realizar algum processamento e cuspir um arquivo .csv. O produto final será um .batarquivo que o usuário final nunca precisará modificar.
Chase

@ Phase, mas você não precisa setwdtrabalhar com caminhos de rede. Você só precisa fornecer caminhos para salvar resultados e ainda trabalhar com o caminho atual (aquele que é estabelecido quando a sessão do R foi iniciada). Ou inicie R com o diretório de trabalho desejado.
Marek

5
Sim. Ou parametrize out_dir <- "path/to/output/directory"e use write.table(file = file.path(out_dir,"table_1.csv"), ...). Ou mesmo out_file <- function(fnm) file.path("path/to/output/directory", fnm)e então write.table(file = out_file("table_1.csv"), ...)(método semelhante que eu uso ao trabalhar com unidades de rede).
Marek

Respostas:


403

Use showWarnings = FALSE:

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

dir.create()não trava se o diretório já existe, apenas imprime um aviso. Portanto, se você consegue ver avisos, não há problema em fazer isso:

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

58
Esteja ciente de showWarnings = FALSEque isso também ocultará outros avisos, como o diretório que não pode ser criado.
precisa saber é o seguinte

5
^ Existe uma maneira de suprimir apenas um aviso específico?
Bas

2
Oi, eu quero ot criar diretório aninhado, como se eu estivesse na pasta test1, em seguida, dentro dela test2 dentro dela test3 ... mas agora estou enfrentando um problema. Existe uma maneira que eu possa criar 3 nível de diretório, mesmo se directory1 não sai?
Praveen Kesani 8/08/16

10
@PraveenKesani É isso que você está procurando dir.create("test1/test2/test3/", recursive=TRUE):?
decano.

6
Resposta muito atrasada do @Bas, mas suppressWarnings(<statement>)suprimirá os avisos apenas para essa afirmação.
Ram RS

163

Em 16 de abril de 2015, com o lançamento de R 3.2.0uma nova função chamada dir.exists(). Para usar esta função e criar o diretório, se não existir, você pode usar:

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

Isso retornará FALSEse o diretório já existir ou não puder ser criado e TRUEse não existir, mas tiver sido criado com êxito .

Observe que, para simplesmente verificar se o diretório existe, você pode usar

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

9
Apenas para observar que não é uma boa prática usar ifelse()para ramificação não vetorizada.
Lionel Henry

2
@ Porque o seu código lê falsamente como se algo vetorizado estivesse acontecendo. É como usar vetorizado em |vez de escalar ||. Funciona, mas é uma má prática.
22716 Lionel Henry

11
Oh droga, então eu tenho feito minhas declarações if erradas também usando |, é a vetorização a razão pela qual ela não funciona ||às vezes? Eu sei que isso está fora de tópico, mas estou ansioso demais para descobrir. Vou defo ir e ler mais sobre vetorização. Obrigado
Bas

4
Então, qual é a melhor maneira de fazer isso se devemos evitar ifelse?
usar o seguinte código

6
usando if e else;)
Lionel Henry

17

Em termos de arquitetura geral, eu recomendaria a seguinte estrutura em relação à criação de diretório. Isso cobrirá a maioria dos problemas em potencial e quaisquer outros problemas com a criação do diretório serão detectados pela dir.createchamada.

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
}

Lembre-se também de que, se ~/foonão existir, uma chamada para dir.create('~/foo/bar')falhará, a menos que você especifique recursive = TRUE.


3
existe um motivo para você usar colar (...) vs arquivo.caminho (mainDir, subDir). Além disso, se você criou um caminho <- file.path (mainDir, subDir), pode reutilizá-lo 5 vezes, tornando as instruções if mais legíveis.
MikeF 26/02

14

Aqui está a simples verificação , e cria a dir se não 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

O uso de file.exists () para testar a existência do diretório é um problema na postagem original. Se o subDir incluísse o nome de um arquivo existente (e não apenas um caminho), file.exists () retornaria VERDADEIRO, mas a chamada para setwd () falharia porque você não pode definir o diretório de trabalho para apontar para um arquivo.

Eu recomendaria o uso de file_test (op = "- d", subDir), que retornará "TRUE" se subDir for um diretório existente, mas FALSE se subDir for um arquivo existente ou um arquivo ou diretório inexistente. Da mesma forma, a verificação de um arquivo pode ser realizada com op = "- f".

Além disso, conforme descrito em outro comentário, o diretório de trabalho faz parte do ambiente R e deve ser controlado pelo usuário, não por um script. Idealmente, os scripts não devem alterar o ambiente R. Para resolver esse problema, eu poderia usar o options () para armazenar um diretório disponível globalmente onde desejava toda a minha saída.

Portanto, considere a seguinte solução, em que someUniqueTag é apenas um prefixo definido pelo programador para o nome da opção, o que torna improvável que uma opção com o mesmo nome já exista. (Por exemplo, se você estava desenvolvendo um pacote chamado "filer", pode usar filer.mainDir e filer.subDir).

O código a seguir seria usado para definir opções disponíveis para uso posterior em outros scripts (evitando assim o uso de setwd () em um script) e para criar a pasta, se necessário:

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

Em qualquer script subseqüente necessário para manipular um arquivo no subDir, você pode usar algo como:

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

Esta solução deixa o diretório de trabalho sob o controle do usuário.


8

Eu tive um problema com o R 2.15.3, ao tentar criar uma estrutura em árvore recursivamente em uma unidade de rede compartilhada, obteria um erro de permissão.

Para contornar essa singularidade, criei manualmente a estrutura;

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

mkdirs("H:/foo/bar")

5

Uma linha:

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

Exemplo:

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

2

Para descobrir se um caminho é um diretório válido, tente:

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

file.info não se importa com uma barra no final.

file.existsno Windows falhará em um diretório se ele terminar em uma barra e for bem-sucedido sem ele. Portanto, isso não pode ser usado para determinar se um caminho é um diretório.

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

O que há de errado nessa resposta (além de não incluir a dir.create()parte)? As declarações estão erradas ou apenas não são úteis para resolver a questão em questão?
mschilli
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.