2012-08-28 122 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