如何在R中实现仅当服务器文件更新时才下载(类curl -z/-R)
解决方案:在R中实现增量文件下载(适配targets流水线)
方法1:用curl包正确配置libcurl参数
你提到的CURLOPT_TIMECOND_IFMODSINCE对应curl包中的timecondition = 1,但还需要配合timevalue参数传入本地文件的修改时间,同时开启filetime来同步服务器文件的修改时间(对应Shell的-R参数)。
完整实现代码如下:
library(curl) # 定义目标文件路径 url <- "https://files.digital.nhs.uk/9B/DF836C/hosp-epis-stat-admi-hosp-prov-2022-23-tab_v2.xlsx" dest_file <- basename(url) # 创建curl handle并配置参数 h <- curl::new_handle() # 检查本地文件是否存在,获取修改时间 if (file.exists(dest_file)) { # 获取本地文件修改时间(转换为Unix时间戳) local_mtime <- file.info(dest_file)$mtime curl::handle_setopt(h, timevalue = as.numeric(local_mtime)) } # 设置时间条件为仅当文件更新时下载(IFMODSINCE) curl::handle_setopt(h, timecondition = 1) # 开启获取服务器文件修改时间,用于同步本地文件时间 curl::handle_setopt(h, filetime = 1) # 执行下载 response <- curl::multi_download( urls = url, destfile = dest_file, handle = h ) # 同步本地文件修改时间为服务器时间(对应-R参数) if (!is.null(response$filetime)) { Sys.setFileTime(dest_file, as.POSIXct(response$filetime, origin = "1970-01-01")) }
关键参数说明:
timecondition = 1:对应CURLOPT_TIMECOND_IFMODSINCE,仅当服务器文件修改时间晚于timevalue指定的时间时才下载。timevalue:传入本地文件的Unix时间戳,作为判断基准。filetime = 1:让curl返回服务器文件的修改时间,之后用Sys.setFileTime同步到本地文件,实现和-R相同的效果。
方法2:直接调用系统curl命令(简单高效)
如果觉得curl包的参数配置太繁琐,可以直接在R中调用你已经验证过的Shell命令,这在targets流水线中同样适用:
library(processx) url <- "https://files.digital.nhs.uk/9B/DF836C/hosp-epis-stat-admi-hosp-prov-2022-23-tab_v2.xlsx" dest_file <- basename(url) # 调用系统curl命令,实现增量下载+同步修改时间 processx::run( command = "curl", args = c("-R", "-z", dest_file, url, "-o", dest_file) )
这种方法完全复用你已经测试过的Shell逻辑,不需要额外学习R curl包的参数,适合快速集成到targets流水线中。
在targets中集成的注意事项
在targets流水线中,你可以将上述代码封装成一个函数,然后定义一个文件目标。targets会根据文件的修改时间自动判断是否需要重新运行该步骤,配合增量下载逻辑能最大限度缩短流水线耗时:
# _targets.R中的示例 library(targets) tar_option_set(packages = c("curl")) download_data <- function() { url <- "https://files.digital.nhs.uk/9B/DF836C/hosp-epis-stat-admi-hosp-prov-2022-23-tab_v2.xlsx" dest_file <- "data/hosp_data.xlsx" dir.create("data", showWarnings = FALSE) # 方法1的curl包实现代码 h <- curl::new_handle() if (file.exists(dest_file)) { local_mtime <- file.info(dest_file)$mtime curl::handle_setopt(h, timevalue = as.numeric(local_mtime)) } curl::handle_setopt(h, timecondition = 1, filetime = 1) response <- curl::multi_download(url, dest_file, handle = h) if (!is.null(response$filetime)) { Sys.setFileTime(dest_file, as.POSIXct(response$filetime, origin = "1970-01-01")) } dest_file } list( tar_target( name = raw_data_file, command = download_data(), format = "file" # 告诉targets这是一个文件目标,基于文件修改时间判断是否更新 ) )
内容的提问来源于stack exchange,提问作者Ollie
相关产品推荐
相关产品推荐

