R Shiny响应式环境下file.copy与loadWorkbook失效但非响应式环境正常
问题核心原因
- 原有下载逻辑中遍历全局临时目录取Excel文件的写法不符合Shiny的会话隔离规则,无法正确定位用户上传的原文件,是
loadWorkbook报错的主要诱因 - 同时加载XLConnect和openxlsx两个Excel处理包会出现
loadWorkbook函数命名冲突,两个包都有同名函数,调用混乱会直接触发报错 - 额外将文件复制到固定命名的
temp_1.xlsx会出现多用户并发访问时的文件覆盖问题,稳定性极差
修复方案
直接读取上传文件的原生临时路径input$file$datapath作为原工作簿,全程用openxlsx处理,不需要额外转存文件,即可完整保留原Excel的所有单元格、工作表格式,再新增工作表写入数据后输出即可,同时修复原有文件格式判断的逻辑错误。
完整可运行代码
library(shiny) library(openxlsx) library(readxl) library(DT) ui <- fluidPage( titlePanel("Writer App"), sidebarLayout( sidebarPanel( fileInput(inputId = "file", label = "Read File Here", accept = c(".xlsx",".csv")), downloadLink("downloadData", "Download") ), mainPanel(DTOutput(outputId = "table1")) ) ) server <- function(input, output) { datasetInput <- reactive({ infile<- input$file if (is.null(infile)) return(NULL) # 修复格式判断逻辑,判断文件名而非文件对象 if(grepl(infile$name, pattern = ".xlsx$" )==T){ data=read_excel(infile$datapath) } else if(grepl(infile$name , pattern = ".csv$" )==T){ data=read.csv(infile$datapath ) } #RENAME DATAFRAME WITH UNDERSCORES names(data)<-gsub(pattern = " ", replacement = "_", x = names(data)) return(data) }) output$table1 <- renderDT({ return(datasetInput()) }) output$downloadData <- downloadHandler( filename = function() { paste("data-", Sys.Date(), ".xlsx", sep="") }, content = function(file) { # 仅处理xlsx格式的原文件,csv上传场景可自行加判断生成新工作簿 req(input$file) if(grepl(input$file$name, pattern = ".xlsx$")){ # 直接读取上传文件的临时路径作为工作簿,完整保留原格式 wb2 <- loadWorkbook(file = input$file$datapath) }else{ # csv上传时新建空白工作簿 wb2 <- createWorkbook() } df_1<-data.frame("DF"= c(1:3)) addWorksheet(wb = wb2,sheetName = "Parameters1") writeData(wb2, "Parameters1", df_1, startCol = 1, startRow = 2, rowNames = TRUE) saveWorkbook(wb2, file, overwrite = TRUE) } ) } shinyApp(ui = ui, server = server)
效果说明
上传带格式的xlsx文件后,下载的文件会完整保留原文件所有工作表的样式、格式、公式等内容,同时新增Parameters1工作表写入指定数据。
内容的提问来源于stack exchange,提问作者Raghavan vmvs
相关产品推荐
相关产品推荐

