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

Я часто нахожу себя пишущим 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))

}

10 ответов

Решение

Использование 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))

По состоянию на 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))

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

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

Один лайнер:

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

С точки зрения общей архитектуры, я бы порекомендовал следующую структуру для создания каталогов. Это покроет большинство потенциальных проблем, и любые другие проблемы с созданием каталога будут обнаружены 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,

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

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

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

mkdirs("H:/foo/bar")

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

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

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

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

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

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

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

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

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

Я знаю, что этот вопрос был задан некоторое время назад, но в случае полезного, herepackage действительно полезен тем, что не нужно ссылаться на определенные пути к файлам и делает код более переносимым. Он автоматически определит ваш рабочий каталог как тот, который вы .Rprojфайл находится в, поэтому часто бывает достаточно следующего, не определяя путь к файлу в вашем рабочем каталоге:

      library(here)

if (!dir.exists(here(outputDir))) {dir.create(here(outputDir))}

Упаковка hutils(который я создал) имеет функции provide.dir(path)а также provide.file(path)для проверки каталогов/файлов на pathсуществуют, создавая их, если они отсутствуют.

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

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"]
Другие вопросы по тегам