Shiny应用临时目录文件读取失败:saveRDS存储后readRDS找不到文件
Shiny应用中readRDS读取模型文件失败问题
背景
这是一个Shiny应用,用户可训练机器学习(ML)模型,通过saveRDS()将模型对象保存为.rds文件到临时目录,之后可查看已保存模型并通过readRDS()读取以进行预测。
问题
调用readRDS()时无法打开文件,提示文件不存在且无法建立连接。
错误信息
Warning in gzfile(file, "rb") : cannot open compressed file '/var/folders/hm/c8hhxwgn2vj0h4qsftqkr_8r0000gn/T//RtmpNpcs7g/Random Forrest18a9141b50ac5.rds', probable reason 'No such file or directory' Warning: Error in gzfile: cannot open the connection
相关代码
保存RDS文件的代码
my_file_name = reactive({ tempfile(pattern = paste0(input$method, x()), fileext = ".rds") # x() 是递增计数器 }) %>% bindEvent(input$save_mod) reactive({ saveRDS(object = my_model(), file = my_file_name()) }) %>% bindEvent(input$save_mod) observeEvent(input$save_mod,{ req(my_file_name()) t = rbind(storage(), list(paste0(input$method, x()), my_file_name()) ) storage(t) # 将模型名称+文件路径存储到数据框供后续使用 })
读取RDS文件的代码
output$test = renderPrint({ req(input$pick_mod) readRDS(storage()[which(storage()[,1]==input$pick_mod), 2]) # which语句从存储表中返回已存储的文件路径 })
问题原因及解决方法
核心原因
- 保存逻辑未执行:原代码中执行
saveRDS的是未被任何对象依赖的响应式(reactive)块,Shiny响应式对象是惰性求值的,只有被其他输出/观察者依赖时才会运行,因此模型文件实际并未被写入。 - 计数器调用时机不一致:生成文件路径和模型名称时两次调用
x(),若x()在这期间递增,会导致存储的模型名称与实际文件路径不匹配。 - 临时文件生命周期限制:
tempfile()生成的临时文件会被系统自动清理,若间隔时间过长再读取,文件可能已被删除。
修复方案
1. 调整保存逻辑到观察者中
将保存操作直接放到observeEvent内,确保点击保存按钮时立即执行:
# 定义存储路径的reactiveVal(可选,用于后续其他地方调用) my_file_name = reactiveVal() observeEvent(input$save_mod,{ req(my_model()) # 先获取当前计数器值,避免后续递增导致不匹配 current_x = x() # 生成文件路径 new_path = tempfile(pattern = paste0(input$method, current_x), fileext = ".rds") # 执行保存 saveRDS(object = my_model(), file = new_path) # 更新路径的reactiveVal my_file_name(new_path) # 更新存储表 t = rbind(storage(), list(paste0(input$method, current_x), new_path) ) storage(t) # 递增计数器 x(current_x + 1) })
2. 改用持久化存储目录(可选)
若需要模型在会话结束后仍能保留,不要使用临时目录,指定一个固定目录并确保其存在:
# 提前创建模型存储目录 dir.create("model_storage", recursive = TRUE, showWarnings = FALSE) observeEvent(input$save_mod,{ req(my_model()) current_x = x() # 使用固定目录路径 new_path = file.path("model_storage", paste0(input$method, current_x, ".rds")) saveRDS(object = my_model(), file = new_path) t = rbind(storage(), list(paste0(input$method, current_x), new_path) ) storage(t) x(current_x + 1) })
3. 验证文件存在性(可选)
读取前先检查文件是否存在,避免报错:
output$test = renderPrint({ req(input$pick_mod) file_path = storage()[which(storage()[,1]==input$pick_mod), 2] if(file.exists(file_path)){ readRDS(file_path) } else { cat("文件不存在,可能已被清理或路径错误") } })
内容的提问来源于stack exchange,提问作者wgraves25
相关产品推荐
相关产品推荐

