【问题标题】:Check existence of directory and create if doesn't exist检查目录是否存在,如果不存在则创建
【发布时间】:2011-05-12 03:10:48
【问题描述】:

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

}

【问题讨论】:

  • 我确定我见过一个 R 函数,它使用随机生成的名称创建一个临时目录并返回该名称。我认为有一个类似的创建临时文件。我找不到它们,但是 Databel 包 (cran.r-project.org/web/packages/DatABEL/index.html) 有一个函数 get_temporary_file_name。
  • 你不应该在 R 代码中使用setwd() - 它基本上违背了使用工作目录的想法,因为你不能再轻松地在计算机之间移动代码。
  • @hadley 有趣的话题值得思考,我很感激你对其他方法的想法。在工作中,所有计算机都同步到同一个网络,因此文件路径是一致的。如果不是这样,我们还有比脚本的可移植性更大的问题要处理。在这个特定的示例中,我正在编写一个脚本,该脚本将加载到一台机器上,该机器将在我们的国家公园周围携带 2 年。该脚本将从本地 SQL 实例中获取数据,进行一些处理,然后输出 .csv。最终产品将是一个.bat 文件,最终用户将永远不必修改。
  • @Marek - 啊,我明白了。所以你是说我应该用类似write.table(file = "path/to/output/directory", ...) 的东西替换我对setwd() 的调用?
  • 是的。或者参数化out_dir &lt;- "path/to/output/directory",然后使用write.table(file = file.path(out_dir,"table_1.csv"), ...)。甚至是out_file &lt;- function(fnm) file.path("path/to/output/directory", fnm),然后是write.table(file = out_file("table_1.csv"), ...)(我在使用网络驱动器时使用的类似方法)。

标签: r


【解决方案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))

【讨论】:

  • 在使用showWarnings = FALSE 时请注意,这也会隐藏其他警告,例如无法创建目录。
  • ^ 有没有办法只抑制一个特定的警告?
  • 嗨,我想创建嵌套目录,比如如果我在文件夹 test1 中,然后在 test2 中,在 test3 中……但现在我遇到了问题。即使 directory1 不退出,有没有办法创建 3 级目录??
  • @PraveenKesani 这是您要找的东西吗:dir.create("test1/test2/test3/", recursive=TRUE)
  • @Bas 确实延迟响应,但 suppressWarnings(&lt;statement&gt;) 将禁止仅针对该语句发出警告。
【解决方案2】:

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

【讨论】:

  • 请注意,将ifelse() 用于非矢量化分支并不是一个好习惯。
  • @Bas 因为您的代码错误地读取,好像正在发生向量化的事情。这就像使用矢量化 | 而不是标量 ||。它有效,但做法不好。
  • 哦该死的,所以我一直在使用 | 做我的 if 语句错误,向量化是它有时不适用于 || 的原因吗?我知道这是题外话,但我太想知道了。我会去阅读更多关于矢量化的信息。谢谢
  • 如果我们应该避免ifelse,那么最好的做法是什么?
  • 使用 if 和 else ;)
【解决方案3】:

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

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

【讨论】:

    【解决方案4】:

    单线:

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

    【讨论】:

      【解决方案5】:

      就一般架构而言,我会推荐以下关于目录创建的结构。这将涵盖大多数潜在问题,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

      【讨论】:

      • 你使用 paste( ... ) vs file.path(mainDir, subDir) 有什么原因吗?此外,如果你做了一个 path
      【解决方案6】:

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

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

      【讨论】:

        【解决方案7】:

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

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

        mkdirs <- function(fp) {
            if(!file.exists(fp)) {
                mkdirs(dirname(fp))
                dir.create(fp)
            }
        } 
        
        mkdirs("H:/foo/bar")
        

        【讨论】:

          【解决方案8】:

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

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

          【讨论】:

          • 这个答案有什么问题(除了不包括dir.create() 部分)?这些陈述是错误的还是被认为无助于解决手头的问题?
          【解决方案9】:

          我知道这个问题是不久前被问到的,但如果有用,here 包对于不必引用特定文件路径并使代码更具可移植性非常有帮助。它会自动将您的工作目录定义为您的 .Rproj 文件所在的目录,因此以下内容通常就足够了,而无需定义工作目录的文件路径:

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

          【讨论】:

            【解决方案10】:

            hutils(我编写的)具有provide.dir(path)provide.file(path) 功能来检查path 处的目录/文件是否存在,如果它们不存在则创建它们。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2015-10-05
              • 2014-07-23
              • 2011-09-15
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多