You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.07 06:21:03