如何使用 write.table 将数据帧下载到漂亮的 csv/Excel 文件中?

How to use write.table to download a dataframe into a nice csv/Excel file?

我正在尝试使用 Shiny downloadHandler() 中的 write.table() 函数,根据底部的可重现代码,将 df 反应性数据帧下载为 .csv 文件。函数 write.table() 允许删除列名(我需要)但会导致非 Excel 输出(问题 #1);另一方面,write.csv() 会产生不错的 Excel 输出,但不允许删除列名(问题 #2)。

有没有办法让 write.table() 为 CSV 正常工作?如果不行,有没有其他办法解决?

此图显示了问题:

可重现代码:

library(dplyr)
library(DT)
library(shiny)
library(shinyWidgets)
library(tidyverse)

ui <-
  fluidPage(fluidRow(
    column(width = 8,
           h3("Click below to download:"),
           downloadButton("sumsDownload","Download",style = "width:20%;"),
           h3("Summed Data:"),
           DT::dataTableOutput("sums")
          )
  ))

server <- function(input, output, session) {
  data <- reactive({
    data.frame(
      Period = c("2020-01", "2020-02", "2020-03", "2020-01", "2020-02", "2020-03"),
      ColA = c(1000.01, 20, 30, 40, 50, 60),
      ColB = c(15.06, 25, 35, 45, 55, 65)
    )
  })
  
  summed_data <- reactive({
    data() %>%
      group_by(!!sym("Period")) %>%
      select("ColA", "ColB") %>% summarise(across(everything(), sum))
  })
  
  output$sums <- renderDT({datatable(data = summed_data(),rownames = FALSE)})
  
  df <- reactive({ # `df` modifies `summed_data` for csv download
    as.data.frame(
      rbind(
        c("Summed Data",rep(NA,ncol(summed_data())-1)),
        colnames(summed_data()),
        matrix(unlist(summed_data(), use.names=FALSE),
               nrow = nrow(summed_data()),
               )
          )
      )
  })
  
  output$sumsDownload <- downloadHandler(
    filename = function() {paste("sumsDownload","csv",sep=".")},
    content = function(file){
      write.table( # change this to write.csv to see Issue #2
        df(),
        na = "", 
        file, 
        col.names = FALSE, # comment out this line if changing to write.csv
        row.names = FALSE)
      }
  )
}

shinyApp(ui, server)

以下是已解决的代码,反映了 2022 年 5 月 5 日之前发布的评论:

library(dplyr)
library(DT)
library(shiny)
library(shinyWidgets)
library(tidyverse)

ui <-
  fluidPage(fluidRow(
    column(width = 8,
           h3("Click below to download:"),
           downloadButton("sumsDownload","Download",style = "width:20%;"),
           h3("Summed Data:"),
           DT::dataTableOutput("sums")
          )
  ))

server <- function(input, output, session) {
  data <- reactive({
    data.frame(
      Period = c("2020-01", "2020-02", "2020-03", "2020-01", "2020-02", "2020-03"),
      ColA = c(1000.01, 20, 30, 40, 50, 60),
      ColB = c(15.06, 25, 35, 45, 55, 65)
    )
  })
  
  summed_data <- reactive({
    data() %>%
      group_by(!!sym("Period")) %>%
      select("ColA", "ColB") %>% summarise(across(everything(), sum))
  })
  
  output$sums <- renderDT({datatable(data = summed_data(),rownames = FALSE)})
  
  df <- reactive({ # `df` modifies `summed_data` for csv download
    as.data.frame(
      rbind(
        c("Summed Data",rep(NA,ncol(summed_data())-1)),
        colnames(summed_data()),
        matrix(unlist(summed_data(), use.names=FALSE),
               nrow = nrow(summed_data()),
               )
          )
      )
  })
  
  output$sumsDownload <- downloadHandler(
    filename = function() {paste("sumsDownload","csv",sep=".")},
    content = function(file){
      write.table( 
        df(),
        na = "", 
        file, 
        sep = ",", # add this per road_to_quantdom on May/05/22
        col.names = FALSE, 
        row.names = FALSE)
      }
  )
}

shinyApp(ui, server)