迭代地重新保存Excel文件的目录树

时间:2015-07-27 13:16:03

标签: r excel xlconnect

我经常从产生非标准Excel格式的来源接收数据,readxl::read_excel无法读取该格式。这是github issue thread。因此,我有一个完整的目录树,其中包含数百个(几乎)Excel文件,我想将其读入R并与plyr::ldply结合使用。然而,XLConnect::loadWorkbook可以很好地打开文件。但不幸的是,即使为Java虚拟机分配了大量内存,它也会在读取几个文件后崩溃。我尝试将这三行添加到导入功能中:

options(java.parameters = "-Xmx16g")
detach("package:XLConnect", unload = TRUE)
library(XLConnect)
xlcFreeMemory()

然而,我仍然得到:

  

错误:OutOfMemoryError(Java):Java堆空间

我需要做的就是在Excel中重新保存它们,然后从readxl::read_excel读取它们。我希望我也可以使用XLConnect批量重新保存它们,然后使用readxl::read_excel读取它们。不幸的是,使用Linux,我只能编写Excel脚本来重新保存它们。有没有人有另一种解决方法?

1 个答案:

答案 0 :(得分:1)

由于您使用的是Linux,因此运行Excel宏来重新保存电子表格看起来很困难。

您可以启动一个单独的R进程来使用XLConnect读取每个电子表格。这可以通过至少两种方式完成:

  • 使用脚本文件运行Rscript,并将其传递给电子表格的名称。将数据保存到.RData文件,然后在主R进程中将其读回。

  • 使用并行包中的parLapply,向其传递电子表格名称向量和读取文件的函数。在这种情况下,您不必将数据作为中间步骤保存到磁盘。但是,您可能必须以块的形式执行此操作,因为除非您重新启动它们,否则从属进程将慢慢耗尽内存。

后者的例子:

files <- list.files(pattern="xlsx$")
filesPerChunk <- 5
clustSize <- 4  # or how ever many slave nodes you want
runSize <- clustSize * filesPerChunk

runs <- length(files)%/%runSize + (length(files)%%runSize != 0)

library(parallel)

sheets <- lapply(seq(runs), function(i) {
    runStart <- (i - 1) * runSize + 1
    runEnd <- min(length(files), runStart + runSize - 1)
    runFiles <- files[runStart:runEnd]

    # periodically restart and stop the cluster to deal with memory leaks
    cl <- makeCluster(clustSize)
    on.exit(stopCluster(cl))

    parLapply(cl, runFiles, function(f) {
        require(XLConnect)
        loadWorkbook(f, ...)
    })
})

sheets <- unlist(sheets, recursive=FALSE)  # convert list of lists to a simple list