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

使用For循环、dplyr和R Shiny开发Excel下载器的报错咨询

问题根因
    1. 你同时允许用户上传csv和xlsx文件,但读取时固定用read.csv(),如果用户上传xlsx文件会读取失败,得到结构异常的空数据,后续取Line Id列时就会触发「下标越界」「if参数长度为0」的报错。
    1. 两个reactivespenddom和tabcreator里的for循环没有累积结果,每次循环都会覆盖上一次的ddf和tabname,最终只返回最后一次循环的结果,完全没法满足一个Line对应一个工作表的需求。
    1. writexl/openxlsx包的写入多工作表功能,需要传入命名列表,列表每个元素对应一个工作表的内容,列表名对应工作表名,你当前传入的是单个数据框和单个工作表名,逻辑完全不匹配。
    1. 重复读取上传文件三次,没必要的同时也增加了IO错误概率。
修复后的完整代码
library(openxlsx) 
library(readxl)
library(writexl) 
library(dplyr) 
library(magrittr)
library(lubridate)
library(shiny) 

ui <- fluidPage(
  titlePanel("Domain Performance"),
  sidebarLayout( 
    sidebarPanel( 
      fileInput('file1', 'Upload file',
                accept=c('text/csv', 
                         'text/comma-separated-values,text/plain', 
                         '.csv','.xlsx'))
    ),
    mainPanel(
      downloadButton('sortspend',"Spend"),
      tableOutput("outdata1")
    )
  ))

server <- function(input, output) {
  
  options(shiny.maxRequestSize=90*1024^2)  
  
  # 公共读取文件的reactive,自动适配csv/xlsx
  raw_data <- reactive({
    req(input$file1)
    file_path <- input$file1$datapath
    file_ext <- tools::file_ext(input$file1$name)
    
    if(file_ext == "csv"){
      df <- read.csv(file_path, check.names = FALSE)
    } else if(file_ext %in% c("xlsx", "xls")){
      df <- read_excel(file_path)
    }
    return(df)
  })
  
  output$outdata1 <- renderTable({
    head(raw_data(), 10) # 只显示前10行避免页面过长
  })
  
  # 处理得到多工作表数据的命名列表
  line_sheet_list <- reactive({
    df <- raw_data()
    line_ids <- unique(df$`Line Id`)
    # 初始化空列表存结果
    res_list <- list()
    for (i in seq_along(line_ids)){
      current_line_id <- line_ids[i]
      ddf <- df %>% 
        select(`Line Id`, Domain, `Advertiser Spending`, Impressions, Clicks, Conversion, Line) %>%
        filter(`Line Id` == current_line_id) %>%
        group_by(Line, Domain) %>%
        summarise(Spend = sum(`Advertiser Spending`), Imp = sum(Impressions), Clicks = sum(Clicks), Conversions = sum(Conversion), .groups = "drop") %>%
        mutate(CPA = ifelse(Conversions == 0, 0, Spend/Conversions)) %>% # 避免转化为0时报除零错
        arrange(desc(Spend))
      # 把结果加入列表,列表名就是工作表名
      res_list[[as.character(current_line_id)]] <- ddf
    }
    return(res_list)
  })
  
  output$sortspend <- downloadHandler(
    filename = function(){
      paste0("domainperfdl_", Sys.Date(), ".xlsx")
    },
    content = function(fname){
      # 命名列表直接传入自动生成多工作表
      write_xlsx(line_sheet_list(), path = fname)
    },
    contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
  )
}

shinyApp(ui=ui, server=server)
额外优化说明
  • 新增文件类型判断逻辑,不管传csv还是xlsx都能正确读取
  • 循环时用列表累积所有Line的处理结果,自动对应工作表名
  • 新增除零保护,当某条域名的转化数为0时CPA直接赋值为0,避免运行警告
  • 输出文件名自动加日期,避免重复覆盖

内容的提问来源于stack exchange,提问作者vinidapooh

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 03:18:05