Search code examples
rcsvfor-loopshinyzip

Read zip file containing multiple .csv tables in R shiny app


I'm working on a shiny app to manipulate data. I'd like to read a zip file selectioned in a fileInput. This zip is composed by multiple csv files, and I'd like to save as reactive values all .csv dataframes. For example, if test.zip contains file ONE.csv, TWO.csv, THREE.csv , i'd like to obtain 3 reactives values (as dataframes) called ONE , TWO, THREE .

I'm abble to do it if I know the name and number of csv files.

But if I don't know the number and names of .csv dataframes, how can I achieve it ?

 ## Only run examples in interactive R sessions
    if (interactive()) {
    
    ui <- fluidPage(
      sidebarLayout(
        sidebarPanel(
          fileInput("ZIP", "Choose ZIP File",
            accept = ".zip"
            )
        ),
        mainPanel(
          DT::dataTableOutput("ONEtab")
        )
      )
    )
    
    server <- function(input, output) {
     ONE <- reactive({
      
      inFile <-req(input$ZIP)
      read_csv(unzip(inFile$datapath,"ONE.CSV"))
      })

      TWO <- reactive({
      
      inFile <-req(input$ZIP)
      read_csv(unzip(inFile$datapath,"TWO.CSV"))
      })

      THREE <- reactive({
      
      inFile <-req(input$ZIP)
      read_csv(unzip(inFile$datapath,"THREE.CSV"))
      })

output$ONEtab <- DT::renderDataTable({ DT::datatable(ONE(), option=list(scrollX=T),filter = 'top')})
    }
    
    shinyApp(ui, server)
    }

Thanks for your help !


Solution

  • One option is to read all the dataframes into a single variable and then use a number to select the one of interest. Here's some code that does this. It uses lapply to read the contents of the zip file to create a reactive variable called all. To reference different dataframes, the code required is all()[[index]] and I have added something that shows this.

    library(DT)
    library(readr)
    ui <- fluidPage(sidebarLayout(sidebarPanel(
        fileInput("ZIP", "Choose ZIP File", accept = ".zip"),
        selectInput("choice", 'Choose', choices = c(1,2,3), selected = 1)
    ),
    mainPanel(DT::dataTableOutput("selectone"))))
    
    server <- function(input, output) {
        all <- reactive({
            inFile <- req(input$ZIP)
            filelist <- unzip(inFile$datapath, list = T)
            lapply(filelist$Name, read_csv)
        })
        
        output$selectone <-
            DT::renderDataTable({
                choice = as.integer(input$choice)
                DT::datatable(all()[[choice]], option = list(scrollX = T), filter = 'top')
            })
    }
    
    shinyApp(ui, server)
    

    Without the rest of your code that processes this, it's difficult to know if this will be what you need but perhaps it's a start.