如何从 R/Shiny 应用程序下载多个文件?
Posted
技术标签:
【中文标题】如何从 R/Shiny 应用程序下载多个文件?【英文标题】:How to download multiple files from R/Shiny app? 【发布时间】:2022-01-19 23:10:49 【问题描述】:关于 SO 的这个主题有许多不同的 Q/A,但我找不到适合我用例的。我也很惊讶 RStudio / Shiny 开发人员自己没有提供一些关于如何做到这一点的文档。无论如何,以这个示例应用程序为例:
library(shiny)
library(glue)
library(tidyverse)
# Define UI for application
ui <- fluidPage(
# Application title
titlePanel("Test Multi-File Download"),
p("I hope this works!"),
downloadButton(
outputId = "download_btn",
label = "Download",
icon = icon("file-download")
)
)
# Define server logic
server <- function(input, output)
#datasets stored in reactiveValues list
to_download <- reactiveValues(dataset1 = iris, dataset2 = airquality, dataset3 = mtcars, dataset4 = NULL)
blahblah <- iris
output$download_btn <- downloadHandler(
filename = function()
paste("my_data_", Sys.Date(), ".csv", sep = "")
,
content = function(file)
#works
#readr::write_csv(blahblah, file)
#Attempt 1
# #create some temp directory
# temp_directory <- tempdir()
# browser()
# reactiveValuesToList(to_download) %>%
# #x is data, y is name
# imap(function(x,y)
# #browser()
# #check if data is not null
# if(!is.null(x))
# #create file name based on name of dataset
# file_name <- glue("y_data.csv")
# #write file to temp directory
# readr::write_csv(x, file_name)
#
# )
# zip::zip(
# zipfile = file,
# files = ls(temp_directory),
# root = temp_directory
# )
)
# Run the application
shinyApp(ui = ui, server = server)
我有一些数据集存储在reactiveValues
列表中,我希望用户能够下载它们。理想情况下,我希望他们能够一次下载多个文件,而不是必须zip
他们,然后下载.zip
文件。我可以接受的另一个选择是将每个数据集添加到 Excel 工作表,然后下载多工作表 Excel 文件。
我的一般思考过程(关于前者)如下:
-
下载按钮被按下
创建一些临时目录
将
to_download
reactiveValues 列表中包含的(不是NULL
)数据集写入此目录
zip
临时目录并下载
我觉得我很接近,但是我还没有能够成功地完成这项工作。有什么想法吗?
编辑 1:我知道建议的答案 here,但想避免使用 setwd()
,因为我认为在 Shiny 应用程序中弄乱工作目录是不好的做法。
【问题讨论】:
这能回答你的问题吗? Download multiple csv files with one button (downloadhandler) with R Shiny @NelsonGon 我已经阅读了这个问题,在我看来,在 Shiny 应用程序中使用setwd()
似乎(非常)不好的做法。如果可能的话,我想避免这种情况。
对于 multi_excel(啊,我被困在 tidyverse_syntax)表中,我认为您可以在按钮单击时循环通过 reactiveVals 并使用 openxl(sx) 或其他一些 excel 编写器写入表。
@NelsonGon 是的,我已经尝试过(使用writexl::write_xlsx()
),其方式与我在imap()
中的注释方式类似,但未能成功提供一些条件来测试是否数据是否为NULL
。
【参考方案1】:
编辑了一些东西,它正在工作:
在zip::zip
调用中使用dir
而不是ls
来显示临时目录的内容(ls
列出了R环境而不是目录内容)
作为进一步的建议:在 tempdir()
内创建一个新的唯一文件夹,以确保仅添加相关文件。
library(shiny)
library(glue)
library(tidyverse)
# Define UI for application
ui <- fluidPage(
# Application title
titlePanel("Test Multi-File Download"),
p("I hope this works!"),
downloadButton(
outputId = "download_btn",
label = "Download",
icon = icon("file-download")
)
)
# Define server logic
server <- function(input, output)
#datasets stored in reactiveValues list
to_download <- reactiveValues(dataset1 = iris, dataset2 = airquality, dataset3 = mtcars, dataset4 = NULL)
blahblah <- iris
output$download_btn <- downloadHandler(
filename = function()
paste("my_data_", Sys.Date(), ".zip", sep = "")
,
content = function(file)
temp_directory <- file.path(tempdir(), as.integer(Sys.time()))
dir.create(temp_directory)
reactiveValuesToList(to_download) %>%
imap(function(x,y)
if(!is.null(x))
file_name <- glue("y_data.csv")
readr::write_csv(x, file.path(temp_directory, file_name))
)
zip::zip(
zipfile = file,
files = dir(temp_directory),
root = temp_directory
)
,
contentType = "application/zip"
)
shinyApp(ui = ui, server = server)
In my own Shiny app 正如您上面建议的那样,我使用了多工作表方法。使用openxlsx
生成多页 xlsx 工作簿的替代设置可能是:
...
output$download_btn <- downloadHandler(
filename = function()
paste("my_data_", Sys.Date(), ".xlsx", sep = "")
,
content = function(file)
wb <- createWorkbook()
reactiveValuesToList(to_download) %>%
imap(function(x,y)
if(!is.null(x))
addWorksheet(wb, sheetName = y)
writeData(wb, x, sheet = y)
)
saveWorkbook(wb, file = file)
,
contentType = "file/xlsx"
)
...
由reprex package 创建于 2021-12-16 (v2.0.1)
【讨论】:
感谢您的帮助,安迪!我很感激。 只是出于好奇,安迪,您对如何将其重构为不需要zip
有任何见解吗?即,一次只下载 3 个文件?
嗯,这是一个很好的问题,我认为超出了正常闪亮工具的范围(download handler takes one file)。您也许可以手动制作一个按钮以通过一些javascript 提示它?我想知道这样做是否有点不礼貌:P
FWIW - 我非常喜欢你的 zip
方法,可能会记下它作为未来应用程序的工具!
是的,同意。 zip
就是这样!再次感谢您的帮助,并感谢您的称赞。以上是关于如何从 R/Shiny 应用程序下载多个文件?的主要内容,如果未能解决你的问题,请参考以下文章
R Shiny Pass 文件列表到 Javascript 下载器
R Shiny:如何从数据表中的自定义按钮调用 JavaScript 函数
从 selectInput 到 facet_wrap 的多个变量:R Shiny
如何使用具有多个输出的 R Shiny moduleServer