Shiny中downloadHandler搭配future_promise报enc2utf8错误如何解决
问题原因
downloadHandler的filename、content参数要求函数同步返回实际值,不支持接收promise对象。你在这两个函数内使用%...>%操作符返回的仍然是未完成的promise,Shiny尝试将promise转为字符型文件名时就会触发enc2utf8报错。
解决方案
调整触发逻辑:先通过普通按钮触发异步计算任务,计算完成后再渲染可用的下载按钮,此时下载需要的文件名、文件内容均为已就绪的普通值,不需要在downloadHandler内处理异步逻辑。
完整可运行代码
--- title: "download with futures fixed" runtime: shiny output: html_document --- ```{r setup, include=FALSE} library(future) library(promises) plan(multisession) library(dplyr) knitr::opts_chunk$set(echo = FALSE)
# 存储异步计算结果和状态 download_data <- reactiveValues( file_meta = NULL, ready = FALSE ) # 渲染触发计算的按钮和下载按钮 renderUI({ tagList( actionButton("start_calc", "生成下载文件"), uiOutput("download_btn_ui") ) }) # 监听按钮点击,触发异步计算 observeEvent(input$start_calc, { # 重置状态 download_data$ready <- FALSE future_promise({ y = rnorm(10) Sys.sleep(5) tf = tempfile(fileext = ".txt") cat(c(y,'\n'), sep='\n', file = tf) d = readBin(con = tf, what = "raw", n = file.size(tf)) return(list(fn = basename(tf), d = d)) }, seed = TRUE) %...>% { # 计算完成后存储结果 download_data$file_meta <- . download_data$ready <- TRUE } }) # 计算完成后渲染下载按钮 output$download_btn_ui <- renderUI({ req(download_data$ready) downloadButton("download_btn", "下载文件") }) # downloadHandler直接读取已就绪的结果,全同步逻辑 output$download_btn <- downloadHandler( filename = function() { download_data$file_meta$fn }, content = function(f) { con = file(description = f, open = "wb") writeBin(object = download_data$file_meta$d, con = con) close(con) } )
改动说明
- 新增
reactiveValues存储异步计算的文件元信息和就绪状态 - 用普通
actionButton触发异步计算任务,避免在downloadHandler中处理异步逻辑 - 异步计算完成后才渲染下载按钮,此时downloadHandler读取的都是已完成计算的普通值,没有promise相关问题
- 异步计算过程中用户可以正常操作界面其他功能,不会阻塞Shiny主进程
内容的提问来源于stack exchange,提问作者richarddmorey
相关产品推荐
相关产品推荐

