R语言使用blastula批量发邮件提示打开文件过多报错如何解决
问题原因
该报错是操作系统的文件句柄占用超限导致:
- blastula的
render_email方法底层依赖rmarkdown渲染Rmd模板,每次渲染都会生成.knit.md中间文件、临时资源文件,同时会占用系统文件句柄 - 现有循环逻辑没有主动释放渲染产生的临时文件和对应句柄,Windows系统默认单进程打开文件句柄上限通常为512,所以循环执行到接近500次时句柄被占满,无法创建新的
alerta.knit.md文件触发报错
解决方案
- 每次循环结束后强制调用垃圾回收
gc(),主动释放未关闭的文件连接和占用的资源 - 每次渲染结束后删除生成的
.knit.md等中间临时文件,避免文件句柄持续占用 - 提前预计算所有循环需要用到的参数,不要在循环内重复执行
distinct()、filter()等操作,既降低资源占用也提高运行效率 - 渲染Rmd时指定输出路径为系统临时目录,避免中间文件残留到工作目录
优化后代码示例
setwd("C:/Users/oscariro/Documents/R/Devoluciones") tempreport <- file.path(getwd(),"Reenvio.rmd") # 预计算所有需要的参数,避免循环内重复计算 usuario_list <- Reenvia %>% select(cta_usuario) %>% distinct() %>% pull(cta_usuario) planta_data <- Planta %>% select(UsuarioCobis, Correo, SBAN, `FUERZA COMERCIAL`) director_cc <- planta_data %>% filter(`FUERZA COMERCIAL`=="DIRECTOR") %>% select(SBAN, Correo) for(i in seq_along(usuario_list)){ print(i) Asesor_ <- usuario_list[i] # 取当前用户的SBAN和收件人 usuario_info <- planta_data %>% filter(UsuarioCobis == Asesor_) %>% slice(1) to_mail <- usuario_info$Correo sban_val <- usuario_info$SBAN # 取抄送人 Nivelcc <- director_cc %>% filter(SBAN == sban_val) %>% pull(Correo) %>% unique() parametros <- list( Comercial = Reenvia %>% filter(cta_usuario==Asesor_) %>% select(nombre_usuario) %>% distinct() %>% as.character(), Asesor_ = Asesor_ ) # 渲染邮件,指定输出到临时目录 email <- blastula::render_email( input = tempreport, render_options = list(params=parametros, output_dir = tempdir()) ) print(parametros$Comercial) tryCatch( email %>% smtp_send( from="xxxxxxxxxxx@xxxxxx.xxxx.xx", to = to_mail, cc = Nivelcc, subject = glue("El motor de alertamientos te informa"), credentials=creds_key("outlook") ), error=function(e) { print(glue("No se le pudo enviar correo a {Asesor_}")) } ) # 清理临时文件+释放资源 unlink(file.path(tempdir(), "*.knit.md"), recursive = TRUE) unlink(file.path(tempdir(), "*_files"), recursive = TRUE) gc() }
内容的提问来源于stack exchange,提问作者Ivan Rojas
相关产品推荐
相关产品推荐

