使用downloadHandler根据上传的数据编辑现有的excel文件吗?

时间:2018-10-16 20:20:20

标签: r excel download shiny

我正在开发一个闪亮的应用程序,在该应用程序中,用户将上传excel文件,将对数据进行操作,然后将导出具有此数据的新excel文件供用户检查。我在downloadHandler函数上遇到问题。我以前每次都基于这样的上传数据创建一个全新的excel文件:

output$export <- downloadHandler(
filename = "answers.xlsx",
content = function(file){
  write.xlsx(exportdata(), file)
     })
  })

这很好。

现在,我想编辑一个Excel文件,该文件将在发布应用程序时包括在内,并允许用户下载此编辑版本,如下所示:

output$export <- downloadHandler(
filename = "answers.xlsx",
content = function(file){
  wb <- loadWorkbook("6rep-charts.xlsx")
  writeData(wb, sheet = "Species Match Results", correlInput())
  writeData(wb, sheet = "BS1 Data", bs1Input())
  writeData(wb, sheet = "BS2 Data", bs2Input())
  saveWorkbook(wb, file)
})

但是,这将导致错误Warning: Error in write_file: Expecting a single string value: [type=character; extent=0]. [No stack trace available]。我不确定出什么问题了,因为当我在闪亮的应用程序外部运行内容部分时,它就可以正常工作。问题似乎出在saveWorkbook命令中。

我想编辑一个现有的excel文件而不是创建一个新的excel文件的原因是,我在应用程序中包含的模板文件已经制作了图表,当将新数据写入文件时该图表应该会更改。用户希望能够自己编辑这些图表,而不仅仅是看到图表。如果有人有更简单的方法来做到这一点,那就太好了!预先感谢您的帮助!

使用this Excel文件的可复制示例:

    library(shiny); library(readxl); library(xlsx)
    ui <- shinyUI(fluidPage(

    titlePanel("Old Faithful Geyser Data"),
    fluidRow(
       column(3,
          downloadButton(outputId = "export",
               label = "Export Results to Excel")
  ),

       column(6,
         dataTableOutput("data")
  ))))

    server <- function(input, output) {
       adata <- faithful[1:20,]   
       bdata <- faithful[21:50,]   
       cdata <- faithful[51:200,]

   read_excel_allsheets <- function(filename, tibble = FALSE) {
      sheets <- readxl::excel_sheets(filename)
      x <- lapply(sheets, function(Y) {readxl::read_excel(filename, sheet = Y)})
      if(!tibble) x <- lapply(x, as.data.frame)
      names(x) <- sheets
      x
   }

   output$data <- renderDataTable({
       adata   })

   output$export <- downloadHandler(
       filename = "answers.xlsx",
       content = function(file){
          wb <- loadWorkbook("./Data/template.xlsx")
          writeData(wb, sheet = "Alpha", adata)
          writeData(wb, sheet = "Beta", bdata)
          writeData(wb, sheet = "Gamma", cdata)
          saveWorkbook(wb, file="./Data/temp.xlsx", overwrite = T)
          print("done")
          Fin_WB<- read_excel_allsheets("./Data/temp.xlsx")
          write.xlsx(Fin_WB, file)
        }   ) }

   shinyApp(ui = ui, server = server)

2 个答案:

答案 0 :(得分:0)

saveWorkbook函数不喜欢用作content函数的写函数。是的,令人困惑,但是我们仍然可以在content函数中使用它,只是不作为最后一步。我们必须使用经典的写入功能,例如write.xlsx才能满足要求写入文件和文件路径的内容功能。

要解决此问题,我们在Data文件夹中创建一个临时文件(此文件夹将位于服务器和ui的目录中,并将被发布)。该程序将读取模板文件(请参见下面的特殊功能),对其进行修改,然后写入/覆盖 temp 文件。然后,该临时文件由read.xlsx读取并分配,然后由write.xlsx写入。这满足了内容功能,并允许我们使用模板进行导出。

read_excel_allsheets <- function(filename, tibble = FALSE) {
    sheets <- readxl::excel_sheets(filename)
    x <- lapply(sheets, function(X) readxl::read_excel(filename, sheet = X))
    if(!tibble) x <- lapply(x, as.data.frame)
    names(x) <- sheets
    x
  }

output$export <- downloadHandler(
    filename = "answers.xlsx",
    content = function(file){
      wb <- loadWorkbook("./Data/template.xlsx")
      writeData(wb, sheet = "Alpha", adata)
      writeData(wb, sheet = "Beta", bdata)
      writeData(wb, sheet = "Gamma", cdata)
      saveWorkbook(wb, file="./Data/temp.xlsx", overwrite = T)
      print("done")
      Fin_WB<- read_excel_allsheets("./Data/temp.xlsx")
      write.xlsx(Fin_WB, file)
    }) 
  }

为了阅读所有表,我们不能简单地使用read.xlsx,因为它不会查看所有表。使用Jeromy Anglim创建的here函数,我们可以阅读excel中的所有图纸。这是read_excel_allsheets函数。

答案 1 :(得分:0)

更简单的解决方案(由于信誉太低,我无法发表评论):

output$export <- downloadHandler(
filename = "answers.xlsx",
content = function(file){
  wb <- loadWorkbook("./Data/template.xlsx")
  writeData(wb, sheet = "Alpha", adata)
  writeData(wb, sheet = "Beta", bdata)
  writeData(wb, sheet = "Gamma", cdata)
  saveWorkbook(wb, file="./Data/temp.xlsx", overwrite = T)
  file.copy(from = "./Data/temp.xlsx", to = file)
}) 

不需要功能 read_excel_allsheets