防止从动态fileInput多次读取文件

时间:2019-08-06 13:37:27

标签: r file-io shiny lapply observers

我已经使用lapply创建了一个动态的FileInput。当我想读取文件时,我也在观察者中使用了lapply。

在这里使用lapply的问题是,每次我上传新文件时都会触发该问题,因此,如果上传了新文件,则会一次又一次读取所有文件。

在这里,我提供了一个Hello World应用程序。 lapply函数取决于我为简单起见而省略的输入参数。

library(shiny)
ui <- fluidPage(
    titlePanel("Hello World"),
    sidebarLayout(
        sidebarPanel(),
        mainPanel(
            lapply(1:2, function(i) {
                fileInput(
                    paste0("file", i),
                    label = NULL,
                    multiple = F,
                    accept = c(
                        "text/csv",
                        "text/comma-separated-values,text/plain",
                        ".csv"
                    ),
                    buttonLabel = paste("File", i)
                )
            }),
            verbatimTextOutput("list")
        )
    )
)

server <- function(input, output) {
    r <- reactiveValues()

    observe({
        lapply(1:2, function(i) {
            file <- input[[paste0("file",i)]]
            if(is.null(file)) return()
            isolate({
                r$file[[paste(i)]] <- readr::read_csv2(file = file$datapath)
            })
        })
    })
    output$list <- renderPrint(reactiveValuesToList(r))
}

shinyApp(ui = ui, server = server)

如何替换循环或对lapply添加要求?

1 个答案:

答案 0 :(得分:1)

虽然我在评论中开始了 cache-invalidation 的道路,但我认为还有其他一些方法可能对您更有效,因为您有固定数量的fileInput字段:交换{代码中的{1}}和lapply行(以及其他一些调整)。

observe

说明:

  • 我正在创建一个反应性块列表,而不是在列表上操作的反应性块。这意味着server <- function(input, output) { lapply(paste0("file", 1:2), function(nm) { observeEvent(input[[ nm ]], { req(input[[nm]], file.exists(input[[nm]]$datapath)) readr::read_csv2(file = input[[nm]]$datapath) }) }) } 将不会对"file1"做出反应。
  • 我通过将"file2"放在paste0(...)的数据中而不是函数中来简化了输入名称的定义,尽管这样做同样容易
    lapply
  • lapply(1:2, function(i) { nm <- paste0("file", i) # ... }) 外部中定义nm很重要,这与延迟的求值和名称空间搜索顺序有关。几年前,我就为此而pre之以鼻,并被Joe Cheng弄清楚:您不能使用observeEvent循环,它一定是这样的保护环境的操作。

N.B .:这是一段代码,还远远不够完整:让forobserve读取数据然后丢弃它是错误的……它丢失了一些东西。理想情况下,这实际上应该是observeEventreactive块,或者处理后的数据应存储在eventReactivereactiveValues中。例如:

reactiveVal

(还有关于防御性编程的另一条注释:您无法完美地控制server <- function(input, output) { mydata <- lapply(paste0("file", 1:2), function(nm) { observeEvent(input[[ nm ]], { req(input[[nm]], file.exists(input[[nm]]$datapath)) readr::read_csv2(file = input[[nm]]$datapath) }) }) observe({ # the following are identical, the latter more declarative mydata[[1]] mydata[["file1"]] }) } 对文件的反应……由于某种原因,它可能会出错。下一步是将其包装在readr::read_csv2中其中tryCatch(..., error = function(e) { errfun(e); NULL; })对错误消息做一些有意义的(将其记录和/或在模式弹出窗口中提供给用户),然后返回errfun(e),以便下游的反应堆可以使用NULL,并且不会尝试处理req(mydata[[1]])

NULL