Проверить наличие директории и создать, если не существует

Я часто нахожу, что пишу сценарии R, которые генерируют много выходных данных. Я считаю, что чище использовать этот вывод в своих собственных каталогах. То, что я написал ниже, будет проверять наличие каталога и перемещаться в него или создавать каталог, а затем перемещаться в него. Есть ли лучший способ приблизиться к этому?

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

Используйте showWarnings = FALSE:

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

dir.create() не сбой, если каталог уже существует, он просто выводит предупреждение. Поэтому, если вы можете жить с предупреждением, нет никаких проблем с этим:

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

Ответ 2

По состоянию на 16 апреля 2015 года с выпуском R 3.2.0 появилась новая функция под названием dir.exists(). Чтобы использовать эту функцию и создать каталог, если он не существует, вы можете использовать:

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

Это вернет FALSE, если каталог уже существует или не доступен, и TRUE, если он не существует, но был успешно создан.

Обратите внимание: чтобы просто проверить, существует ли каталог, вы можете использовать

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

Ответ 3

Что касается общей архитектуры, я бы рекомендовал следующую структуру в отношении создания каталога. Это затронет большинство потенциальных проблем, и любые другие проблемы с созданием каталогов будут обнаружены вызовом dir.create.

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
}

Также имейте в виду, что если ~/foo не существует, вызов dir.create('~/foo/bar') завершится с ошибкой, если вы не укажете recursive = TRUE.

Ответ 4

Здесь простая проверка, и создает каталог, если он не существует:

## 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!")
}

Ответ 5

Использование файла file.exists() для проверки наличия каталога является проблемой в исходном сообщении. Если в subDir было указано имя существующего файла (а не только путь), file.exists() вернет TRUE, но вызов setwd() завершится неудачно, потому что вы не можете установить рабочий каталог в файл.

Я бы рекомендовал использовать file_test (op = "- d", subDir), который вернет "TRUE", если subDir - это существующий каталог, но FALSE, если subDir - это существующий файл или несуществующий файл или каталог, Аналогично, проверка файла может быть выполнена с помощью op = "- f".

Кроме того, как описано в другом комментарии, рабочий каталог является частью среды R и должен контролироваться пользователем, а не script. Сценарии должны, в идеале, не изменять среду R. Чтобы решить эту проблему, я мог бы использовать options() для хранения доступного в глобальном масштабе каталога, где мне нужен весь мой вывод.

Итак, рассмотрим следующее решение, где someUniqueTag - только определенный программистом префикс для имени опции, что делает маловероятным, что опция с тем же именем уже существует. (Например, если вы разрабатывали пакет под названием "filer", вы можете использовать filer.mainDir и filer.subDir).

Следующий код будет использоваться для установки параметров, доступных для использования позднее в других сценариях (таким образом, избегая использования setwd() в script) и при необходимости создайте папку:

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

Затем в любом последующем script, который должен был обрабатывать файл в subDir, вы можете использовать что-то вроде:

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

Это решение оставляет рабочий каталог под контролем пользователя.

Ответ 6

У меня возникла проблема с R 2.15.3, когда при попытке создать рекурсивную структуру дерева на общем сетевом диске я получил бы ошибку разрешения.

Чтобы обойти эту странность, я вручную создаю структуру;

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

mkdirs("H:/foo/bar")

Ответ 7

Чтобы выяснить, является ли путь действительным каталогом, попробуйте:

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

file.info не заботится о косой черте на конце.

file.exists в Windows не удастся для каталога, если он заканчивается косой чертой, и без нее удастся. Поэтому это невозможно использовать для определения того, является ли путь каталогом.

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

Ответ 8

Один лайнер:

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

Пример:

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