【问题标题】:Switching writing from file to stdout using "sink()" in R在 R 中使用“sink()”从文件切换到标准输出
【发布时间】:2013-11-07 13:15:12
【问题描述】:

我实现了以下过程,旨在写入一些文件并在写入完成后在每个文件的末尾打印一条消息:

# Print one file per piaf
output_dir_piafs <- "OUTPUT_dataset_piafs"
unlink(output_dir_piafs, recursive = TRUE, force = TRUE)
dir.create(output_dir_piafs)
for (i in 1:length(lst_sorted)) {
    sink()      # Generates warnings...
    filename <- paste(output_dir_piafs, "/piaf_", i, ".txt", sep="")
    sink(file = filename, append = TRUE)
    sink(type = "message")
    cat("  ", colnames(file1), "\n")

    for (j in 1:length(lst_sorted[[i]])) {
        cat(j, " ")
        lapply( lst_sorted[[i]][[j]], 
                function(x) { 
                    cat(as.character(x), " ")
                }
        )
        cat("\n")
    }

    ## back to the console
    sink()
    cat(paste(filename, "done !\n"))
    #flush(stdout())        # Tested, no particular effect
}

我的问题是,如果我不在循环的最开始添加sink(),则标准输出(cat(paste(filename, "done !\n")))上的最终写入将无效。另一方面,早点添加sink() 会产生我想避免的警告:

There were 50 or more warnings (use warnings() to see the first 50)
> warnings()
Warning messages:
1: In sink() : no sink to remove
2: In sink() : no sink to remove
3: In sink() : no sink to remove

有人知道 sink() 的行为方式和/或如何消除这些警告吗?

注意:我也试过try(sink(), silent=TRUE),但silent 选项只能防止错误...

【问题讨论】:

  • 只是一个愚蠢的想法。您是否从新的 R 会话中尝试过您的代码?也许你有一些连接打开,试试sink.number("message")
  • 好主意! sink.number("message") 不返回任何内容,但是从一个全新的会话中,标准输出可以正常写入。只有当我停止进程 (Ctrl-C),然后重新运行它时,标准输出才会失败。所以,我认为你是对的。我的坏处:中断进程可能会对stdout 连接产生一些不良后果。此外,如果我在重新运行该过程之前输入sink(),它仍然不起作用......
  • 我做了一些其他的测试。如果我让进程正确终止,然后重新运行它,一切正常。这绝对是产生问题的Ctrl-C 中断。在以这种方式打断之后,关于如何使事情变得正确有什么建议吗?
  • 去过那里,做过那个,买了T恤,不喜欢。很高兴您解决了您的问题。

标签: r file stdout keyboardinterrupt sink


【解决方案1】:

你不用sink,看看?cat,可以直接写入文件。

以下代码应该可以工作:

output_dir_piafs <- "OUTPUT_dataset_piafs"
unlink(output_dir_piafs, recursive = TRUE, force = TRUE)
dir.create(output_dir_piafs)
lst_sorted <- c(1,2,3)
file1 <- c(a=1, b=2, c=3)
for (i in 1:length(lst_sorted)) {
  filename <- paste(output_dir_piafs, "/piaf_", i, ".txt", sep="")
  cat("  ", colnames(file1), "\n", file=filename, append=T)
  for (j in 1:length(lst_sorted[[i]])) {
    cat(j, " ", file=filename, append=T)
    lapply( lst_sorted[[i]][[j]], 
           function(x) { 
             cat(as.character(x), " ", file=filename, append=T)
           }
           )
    cat("\n", file=filename, append=T)
  }
  cat(paste(filename, "done !\n"))
}

请注意,我设置变量lst_sortedfile1 是为了使代码可重现。

cat 解决方案是否适合您?

【讨论】:

  • 是的,它可以工作,但是将数据写入文件所需的时间也是sink 的两倍。这很烦人......我想这样做会导致在每个cat打开/关闭文件连接。
  • 关于速度,只需在循环之前创建 f
  • @KarlForner 好的,谢谢!这可以使cat user1981275 的解决方案可行。我们将看看Ctrl-C中断是否仍然需要关闭tryCatch中的文件...
  • @user1981275 感谢您的帮助!只是备注:cat("\n"),也应该写在文件中:cat("\n", file=filename, append=T)
【解决方案2】:

我终于通过在捕获中断时添加sink(type="output") 解决了这个问题 - Ctrl-C - (这使得事情适合以后使用标准输出 - 否则将保持锁定/转移):

tryCatch({

    # Print one file per piaf
    output_dir_piafs <- "OUTPUT_dataset_piafs"
    unlink(output_dir_piafs, recursive = TRUE, force = TRUE)
    dir.create(output_dir_piafs)
    for (i in 1:length(lst_sorted)) {
        filename <- paste(output_dir_piafs, "/piaf_", i, ".txt", sep="")
        sink(file = filename, append = TRUE)
        sink(type = "message")
        cat("  ", colnames(file1), "\n")

        for (j in 1:length(lst_sorted[[i]])) {
            cat(j, " ")
            lapply( lst_sorted[[i]][[j]], 
                    function(x) { 
                        cat(as.character(x), " ")
                    }
            )
            cat("\n")
        }

        ## back to the console
        sink(type="output")
        cat(paste(filename, "done !\n"))
    }

}, interrupt = function(ex) {

    ##cat("An interrupt was detected.\n")
    sink(type="output")            # Restore the standard output !
    ##print(ex)

}) # tryCatch()


另一种方法(基于user1981275Karl Forner 的帮助)是:

tryCatch({

    # Print one file per piaf
    output_dir_piafs <- "OUTPUT_dataset_piafs_2"
    unlink(output_dir_piafs, recursive = TRUE, force = TRUE)
    dir.create(output_dir_piafs)
    for (i in 1:length(lst_sorted)) {
        filename <- paste(output_dir_piafs, "/piaf_", i, ".txt", sep="")
        f <- file(filename, 'w')
        cat("  ", colnames(file1), "\n", file=f)

        for (j in 1:length(lst_sorted[[i]])) {
            cat(j, " ", file=f)
            lapply( lst_sorted[[i]][[j]], 
                    function(x) { 
                        cat(as.character(x), " ", file=f)
                    }
            )
            cat("\n", file=f)
        }

        flush(f)
        close(f)
        ## back to the console
        cat(paste(filename, "done !\n"))
    }

}, interrupt = function(ex) {

    closeAllConnections()

}) # tryCatch()

此解决方案的最大优势在于不转移标准输出,这意味着即使没有捕获中断,标准输出仍保持活动状态。

请注意,键盘中断处理仍然是必要的,以避免出现如下警告:

> warnings()
Warning message:
closing unused connection 3 (OUTPUT_dataset_piafs_2/piaf_16.txt)

?closeAllConnections

‘closeAllConnections’关闭(并销毁)所有用户连接, 恢复所有“汇”转移。

最后一点:这两种方法在文件写入方面没有真正的速度差异。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-11-05
    • 1970-01-01
    • 1970-01-01
    • 2015-08-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-28
    相关资源
    最近更新 更多