r-vroom id参数-使用文件名而不是归档文件名

  • 本文关键字:文件名 id 参数 r-vroom r vroom
  • 更新时间 :
  • 英文 :


我想用vroom读取一个远程归档文件,并用文件名而不是归档名称获得一个额外的列。在没有本地archive_extract步骤的情况下使用vroom是否可能实现这一点,如下例所示?

谢谢

library(tidyverse)
library(archive)
library(vroom)
file <-  "ftp://opendata.dwd.de/climate_environment/CDC/grids_germany/daily/regnie/ra2021m.tar"
test1 <- vroom_fwf(file,  col_positions = fwf_widths(rep(4, 611)),
col_types = , cols(.default = col_integer()),
na = "-999", id = "filename")
test1$filename %>% unique()
#> [1] "ftp://opendata.dwd.de/climate_environment/CDC/grids_germany/daily/regnie/ra2021m.tar"
my_dir <- fs::file_temp() %>% fs::dir_create()
archive_extract(file, dir = my_dir)
test2 <- fs::dir_ls(my_dir)  %>%
vroom_fwf(  col_positions = fwf_widths(rep(4, 611)),
col_types = , cols(.default = col_integer()),
na = "-999", id = "filename") 
test2$filename %>% unique()
#>   [1] ".../AppData/Local/Temp/Rtmp2TTpuI/filebfd82b6b1f6/ra210101.gz"
#>   [2] ".../AppData/Local/Temp/Rtmp2TTpuI/filebfd82b6b1f6/ra210102.gz"
#>   [3] ".../AppData/Local/Temp/Rtmp2TTpuI/filebfd82b6b1f6/ra210103.gz"
...

创建于2022-07-25由reprex包(v2.0.1(

这就是vroom渐晕图所建议的:

从多个多文件zip档案中读取单个文件

如果您正在读取包含多个文件的zip文件相同的格式,您可以使用这样的包装函数:

read_all_zip <- function(file, ...) {
filenames <- unzip(file, list = TRUE)$Name
vroom(purrr::map(filenames, ~ unz(file, .x)), ...)
}

根据您的用例进行调整,这提供了类似于:

read_all_tar_remote_v1 <- function(file) {
con <- file(file, open = "rb")
filenames <- untar(con, list = T)
df <- purrr::map(filenames,~ vroom_fwf(archive_read(file, file = .x, format='tar'),
col_positions = fwf_widths(rep(4, 611)),
col_types = , cols(.default = col_integer()),
na = "-999", id = "filename", guess_max=2000))
df
}
read_all_tar_remote_v1(file)

然而,这很慢(而且由于我的互联网连接不好,经常会崩溃(,因为如上所述,untar需要读取整个归档文件才能获得文件名。

这个确实下载了整个存档,因为untar需要读取整个文件才能查看其中的内容。tar文件中没有供untar读取的主目录;每个文件总是有自己的512字节的头块。你不需要把它保存到硬盘上就可以读取目录,但这样做可能同样容易

我想,这就是你的问题。

避免这种情况的一种方法是将archive_read与索引位置一起使用。

read_all_tar_remote_v2 <- function(file) {
df <- purrr::map(1:365,~ vroom_fwf(archive_read(file, file = .x, format='tar'),
col_positions = fwf_widths(rep(4, 611)),
col_types = , cols(.default = col_integer()),
na = "-999", id = "filename", guess_max=2000))
df
}

不过,这并没有给你确切的文件名,但至少有一个索引可以让你区分它们。这是您当前实现的唯一改进。

mylist <- read_all_tar_remote_v2(file)
mylist[[1]]$filename %>% unique
[1] "archive_read(ftp://opendata.dwd.de/climate_environment/CDC/grids_germany/daily/regnie/ra2021m.tar)[1]"

由于在读取之前您可能不知道文件的数量,因此您可能希望在函数中包含错误管理。

read_all_tar_remote_v3 <- function(file, maxfiles = 10000) {
mylist <- list()
for (i in 1:maxfiles) {
print(paste('reading file', i,'/', maxfiles))
#ERROR HANDLING
possibleError <- tryCatch({
mydf <- vroom_fwf(archive_read(file, file = i, format='tar'),
col_positions = fwf_widths(rep(4, 611)),
col_types = , cols(.default = col_integer()),
na = "-999", id = "filename", guess_max=2000)
mylist[[i]] <- mydf
},
error=function(e) e
)

if(inherits(possibleError, "error")){
break
} 
}
return(mylist)
}

这比你目前的方法更快还是更好?我让你决定,但我不会这么说。

我会继续提取单个文件,因为不幸的是,不完整读取名称似乎是tar格式的限制。

最新更新