如何在`untar(files="xxx")`指定文件不存在时实现静默输出?
解决Windows下
utils::untar()提取不存在文件时的tar.exe错误信息问题 问题概述
在Windows 10的R 4.1.3环境中,使用utils::untar()的files参数提取单个文件时,若目标文件不存在,除了R抛出的警告外,还会输出tar.exe:开头的系统级错误信息。suppressWarnings()仅能消除R的警告,无法屏蔽这类系统输出;而使用tar="internal"参数虽能避免错误信息,但会生成多余的空目录,频繁调用时删除目录会拉低运行效率。
可复现示例
提取存在的文件(正常场景)
library(glue) tmp = tempdir() target = glue("{tmp}/spelling_2.2.tar.gz") download.file("https://cran.r-project.org/src/contrib/Archive/spelling/spelling_2.2.tar.gz", destfile=target) untar(target, files="spelling/DESCRIPTION", exdir=glue("{tmp}/extract1_ok")) list.files(glue("{tmp}/extract1_ok"), recursive=TRUE) |> head() #> [1] "spelling/DESCRIPTION" list.dirs(glue("{tmp}/extract1_ok"), recursive=TRUE, full.names=FALSE) |> head() #> [1] "" "spelling"
提取不存在的文件(问题场景)
untar(target, files="xxx.zzz", exdir=glue("{tmp}/extract1_missing")) #> tar.exe: xxx.zzz: Not found in archive #> tar.exe: Error exit delayed from previous errors. #> Warning in untar(target, files = "xxx.zzz", exdir = glue("{tmp}/extract1_missing")): 'tar.exe -xf #> "C:\\Users\\Dan\\AppData\\Local\\Temp\\RtmpQ3jdcY/spelling_2.2.tar.gz" -C #> "C:/Users/Dan/AppData/Local/Temp/RtmpQ3jdcY/extract1_missing" "xxx.zzz"' #> returned error code 1 list.files(glue("{tmp}/extract1_missing"), recursive=TRUE) |> head() #> character(0) list.dirs(glue("{tmp}/extract1_missing"), recursive=TRUE, full.names=FALSE) |> head() #> [1] ""
使用tar="internal"的副作用
untar(target, files="spelling/DESCRIPTION", exdir=glue("{tmp}/extract_internal"), tar="internal") list.files(glue("{tmp}/extract_internal"), recursive=TRUE) |> head() #> [1] "spelling/DESCRIPTION" list.dirs(glue("{tmp}/extract_internal"), recursive=TRUE, full.names=FALSE) |> head() #> [1] "" "spelling" #> [3] "spelling/inst" "spelling/inst/templates" #> [5] "spelling/man" "spelling/R"
解决方案
默认调用的Windows系统tar.exe会将错误信息输出到标准错误流(stderr),我们可以通过重定向stderr到nul来屏蔽这类输出。以下是封装好的自定义函数,兼顾抑制R警告与系统错误输出,同时不会生成多余空目录:
silent_untar <- function(tarfile, files, exdir = ".") { # 构造tar命令,将stderr重定向到nul(Windows专属) tar_cmd <- glue::glue( 'tar.exe -xf "{tarfile}" -C "{exdir}" "{files}" 2>nul' ) # 执行命令并抑制R层面的警告 suppressWarnings(system(tar_cmd, intern = FALSE)) }
函数测试
# 测试提取不存在的文件:无任何输出 silent_untar(target, files="xxx.zzz", exdir=glue("{tmp}/extract_silent")) list.files(glue("{tmp}/extract_silent"), recursive=TRUE) |> head() #> character(0) # 测试提取存在的文件:正常输出结果,无多余目录 silent_untar(target, files="spelling/DESCRIPTION", exdir=glue("{tmp}/extract_silent_ok")) list.files(glue("{tmp}/extract_silent_ok"), recursive=TRUE) |> head() #> [1] "spelling/DESCRIPTION" list.dirs(glue("{tmp}/extract_silent_ok"), recursive=TRUE, full.names=FALSE) |> head() #> [1] "" "spelling"
这个方案无需额外删除目录操作,适合高频调用的场景。
内容的提问来源于stack exchange,提问作者Dan Chaltiel
相关产品推荐
相关产品推荐

