2

目标是使用 OpenXLSX 将数据添加到现有的 Excel 文件中,然后使用 RDCOMClient 在同一个 Excel 文件中运行宏,并在此过程中从 R 脚本中保存它。

Excel 宏对数据加载后必须发生的数据透视表过滤器和折叠点进行更改。

这个小问题的重现没有问题:

library(openxlsx)
library(RDCOMClient)

ds <- cars
tmpl <- './templates/templatetest.xlsm'
datatab <- 'data'
datarng <- 'pdata'
fn <- paste0("./WAR/", "test1.xlsm")

wb <- loadWorkbook(tmpl)
writeData(wb, datatab, ds)
saveWorkbook(wb, fn, overwrite = TRUE)
rm(wb)

# note this doesn't reveal the full actual UNC path
fn <- paste0("./WAR/",
             "test1.xlsm")


xlApp <- COMCreate("Excel.Application")
xlWbk <- xlApp$Workbooks()$Open(fn)

# run macros
xlApp$Run("clear_pt_filters")
xlApp$Run("CollapsePivotFields")
xlApp$Run("toggle_alcItems")

# Close the workbook and quit the app:
xlWbk$Close(TRUE)
xlApp$Quit()

# Release resources:
rm(xlWks, xlWbk, xlApp)
gc()

但是,在生产中运行时,我在第一宏行出现错误:

xlApp$Run("clear_pt_filters")

.COM(x,名称,...)中的错误:无法找到 0 个名称在 COM 对象中运行(状态 = -2147418111)

我怀疑这是由于加载 1-2 MB 文件的时间,而 R 在没有 RDCOMClient 已准备好宏运行请求的信号的情况下继续进行。

我通过从同一宏行开始再次运行脚本来手动解决此问题。最后,错误只是阻止了完全自动化,电子表格完全符合预期。

编辑:如果我逐行执行“生产”版本,则没有错误。

我的问题是 1)错误的原因是什么,以及 2)我可以做些什么来解决自动化问题?

谢谢。

4

2 回答 2

2

发现我正在使用的最简单的解决方案是使用 Sys.sleep() 插入一秒钟的暂停。

Sys.sleep(1)

所以,从上面看,它看起来像这样,编辑过:

xlApp <- COMCreate("Excel.Application")
xlWbk <- xlApp$Workbooks()$Open(fn)

# run macros
Sys.sleep(1)
xlApp$Run("clear_pt_filters")
xlApp$Run("CollapsePivotFields")
xlApp$Run("toggle_alcItems")

# Close the workbook and quit the app:
xlWbk$Close(TRUE)
xlApp$Quit()

# Release resources:
rm(xlWbk, xlApp)
gc()

归功于R 中是否有“暂停”功能?

于 2017-06-07T18:24:48.637 回答
1

我想问题是 saveWorkbook() 函数旨在以 xlsx 格式保存,并且可能不保留工作簿中的宏信息。更好的方法是使用 RDCOMClient 完全处理这个问题。可能通过这样的方法。

library(openxlsx)
library(RDCOMClient)

ds <- cars
tmpl <- './templates/templatetest.xlsm'
newfile <- './templates/templatetestNEW.xlsm'

# Create Excel instance
xlApp <- COMCreate("Excel.Application")

# Open workbook template
xlWB <- xlApp$Workbooks()$Open(tmpl)

# Select the "data" Sheet
xlSheet <- xlWB$Sheets("data")

# Create a dataframe from headers
headers <- t(as.data.frame(colnames(ds)))
# Set range for headers
rng <- xlSheet$Range(xlSheet$Cells(1, 1),xlSheet$Cells(1, ncol(headers)))
# Insert headers
rng[["Value"]] <- asCOMArray(headers)

# Set range for data values
rng <- xlSheet$Range(xlSheet$Cells(2, 1),xlSheet$Cells(nrow(ds)+1, ncol(ds)))

# Add data to Excel sheet
rng[["Value"]] <- asCOMArray(ds)

# Save Workbook
xlWB$SaveAs(gsub("/","\\\\",newfile))

# run macros
xlApp$Run("clear_pt_filters")
xlApp$Run("CollapsePivotFields")
xlApp$Run("toggle_alcItems")

# Close the workbook and quit the app:
xlWbk$Close(TRUE)
xlApp$Quit()

# Release resources:
rm(xlWks, xlWbk, xlApp)
gc()
于 2017-05-31T20:23:58.820 回答