2012-08-28 121 views
3

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

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会话。

关于如何从一个通用函数中成功完成任何想法或者是否存在其他一些问题?

+1

IIRC删除指定为COM对象的对象仅删除指针,但不关闭对象。尝试将所有启动为对象的对象设置为NULL,然后手动调用gc()。例如。在excel和wb等之上。 – Hansi

回答

2

这是对你的代码应该工作的一个小小的改变(我现在在Linux上,所以我不能测试它)。 主要的修正是将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") 

    # 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函数中删除。这并不好。

OK,有非常微妙的问题在起作用,所以这里没有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!" 
+0

我会用rm替换excelobj(excelobj,envir = excel)? – abhisarihan

+0

糟糕,错字。应该是'rm(“instance”,envir = excel)'。现在修复。 – Tommy

+0

虽然这个解决方案有效,但我希望通过传入@Tommy建议的环境来调用清理函数来推广代码清理。我必须在多个地方执行此调用,并且宁愿不必手动将每个对象都设置为NULL。我确实注意到,随着汤米的建议和我的原始代码,cleanupexcel(myexcel)调用删除对象,但不知何故不执行gc。如果我从cleanupexcel返回后手动调用gc(),它就会起作用。关于为什么gc()在cleanupexcel中表现不正确的任何想法? – abhisarihan