提问



我经常发现自己编写的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))

}

最佳参考


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

其它参考1


截至2015年4月16日,随着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))

其它参考2


就通用架构而言,我建议在目录创建方面采用以下结构。这将涵盖大多数潜在问题,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不存在,则除非指定recursive = TRUE,否则对dir.create('~/foo/bar')的调用将失败。

其它参考3


使用file.exists()来测试目录的存在是原始帖子中的一个问题。如果subDir包含现有文件的名称(而不仅仅是路径),则file.exists()将返回TRUE,但是对setwd()的调用将失败,因为您无法将工作目录设置为指向文件。


我建议使用file_test(op=- d,subDir),如果subDir是现有目录,则返回TRUE,但如果subDir是现有文件或不存在的文件或目录,则返回FALSE。同样,可以使用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))


此解决方案使工作目录处于用户的控制之下。

其它参考4


我遇到了R 2.15.3的问题,在尝试在共享网络驱动器上递归创建树结构时,我会收到权限错误。


为了解决这个奇怪的问题,我手动创建结构;


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

mkdirs("H:/foo/bar")

其它参考5


这是简单检查并创建目录,如果不存在:


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

其它参考6


要确定路径是否是有效目录,请尝试:


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


file.info并不关心最后的斜线。


如果目录以斜杠结尾,则Windows上的file.exists将失败,如果没有它,则会成功。因此,这不能用于确定路径是否是目录。


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