3

我希望能够从 R 打开一个 excel 会话,写入它,然后从 R 关闭 excel 会话。虽然我可以在同一个函数中完成这一切,但我正在尝试概括用于清理 excel 的代码。但是,不知何故,当我通过传入 excel 对象从函数调用 gc() 时,它不会进行垃圾收集。下面是代码:

opentest<-function() {
    excel<-comCreateObject("Excel.Application")
    comSetProperty(excel,"Visible",T)
    comSetProperty(excel,"DisplayAlerts",FALSE)

    comSetProperty(excel, "SheetsInNewWorkbook", 1)
    wb <- comGetProperty(excel, "Workbooks")
    wb <- comInvoke(wb, "Add")
    excel
}

cleanupexcel<-function(excelobj) {
    comInvoke(excelobj,"Quit")
    rm(excelobj, envir=globalenv()) 
    eapply(env=globalenv(), gc)
}

通过以下对函数的调用:

excelobj<-  opentest()
cleanupexcel(excelobj)

当我调用上面的两个函数时,我仍然可以在我的任务管理器中看到正在运行的 excel 会话。但是,如果我在从 cleanupexcel() 返回后调用 gc(),它会成功终止 excel 会话。

关于如何从通用函数中成功 gc 的任何想法,或者我在这里还有其他问题吗?

4

1 回答 1

2

这是对您的代码的一个小改动,应该可以工作(我现在在 Linux 上,所以我无法测试它)。主要解决方法是将 excel 实例包装在一个环境中并返回它。

然后 close 可以访问该实例,然后在调用之前将其删除(确保不保留对它的引用)gc()

opentest<-function() {
    excel<-comCreateObject("Excel.Application")
    comSetProperty(excel,"Visible",T)
    comSetProperty(excel,"DisplayAlerts",FALSE)

    comSetProperty(excel, "SheetsInNewWorkbook", 1)
    wb <- comGetProperty(excel, "Workbooks")
    wb <- comInvoke(wb, "Add")

    # wrap excel in an environment
    env <- new.env(parent=emptyenv())
    env$instance <- excel
    env
}

cleanupexcel<-function(excel) {
    comInvoke(excel$instance,"Quit")
    rm("instance", envir=excel)
    gc() 
}

myexcel <- opentest()
cleanupexcel(myexcel)

...请注意,您的旧代码需要将变量命名为“excelobj”,因为您将其从cleanupexcel函数中删除。那不是很好。

好的,有非常微妙的问题在起作用,所以这是一个没有 excel 的可重现示例:

opentest<-function() {
    excel<-new.env()
    reg.finalizer(excel, function(x) { cat("FINALIZING EXCEL!\n") }, FALSE)

    # wrap excel in an environment
    env <- new.env(parent=emptyenv())
    env$instance <- excel
    env
}

cleanupexcel<-function(excel) {
    cat(excel$instance,"\n")
    rm("instance", envir=excel)
    gc() 
}

myexcel <- opentest()
cleanupexcel(myexcel)
# Prints "FINALIZING EXCEL!"
于 2012-08-28T22:03:51.517 回答