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

241

Я часто нахожу, что пишу сценарии 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
    Я уверен, что видел функцию R, которая создает временный каталог со случайно сгенерированным именем и возвращает имя. Я думаю, что есть аналогичный файл, который создает временный файл. Я не могу найти их от случая к случаю, но в пакете Databel ( cran.r-project.org/web/packages/DatABEL/index.html ) есть функция get_teilitary_file_name.
  • 34
    Вы никогда не должны использовать setwd() в коде R - это в основном setwd() идею использования рабочего каталога, потому что вы больше не можете легко перемещать свой код между компьютерами.
Показать ещё 6 комментариев
Теги:

7 ответов

258
Лучший ответ

Используйте 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))
  • 48
    При использовании showWarnings = FALSE что это также скроет другие предупреждения, например, что каталог не может быть создан.
  • 4
    ^ Есть ли способ подавить только одно конкретное предупреждение?
Показать ещё 3 комментария
93

По состоянию на 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))
  • 9
    Просто отметим, что не рекомендуется использовать ifelse() для не векторизованного ветвления.
  • 0
    В чем дополнительное преимущество использования dir.exists() перед file_test("-d", dir) предложенного @G Poole? Я предпочитаю использовать последний, потому что он обратно совместим.
Показать ещё 9 комментариев
15

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

  • 1
    есть ли причина, по которой вы используете paste (...) vs file.path (mainDir, subDir). Также, если вы указали путь <- file.path (mainDir, subDir), вы можете использовать его 5 раз, делая операторы if более читабельными.
6

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

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

5

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

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

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

mkdirs("H:/foo/bar")
2

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

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

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

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"]
  • 0
    Что не так в этом ответе (кроме части dir.create() )? Являются ли утверждения неправильными или просто считаются бесполезными для решения поставленного вопроса?

Ещё вопросы

Сообщество Overcoder
Наверх
Меню