有没有理由我无法直接从zip文件中读取RDS文件,而不必先将其解压缩到磁盘上的临时文件中?
假设这是zip文件:
saveRDS(cars, "cars.rds")
saveRDS(iris, "iris.rds")
write.csv(iris, "iris.csv")
zip("datasets.zip", c("cars.rds", "iris.rds", "iris.csv"))
file.remove("cars.rds", "iris.rds", "iris.csv")
对于csv文件,我可以直接读取它:
iris2 <- read.csv(unz("datasets.zip", "iris.csv"))
但是,我不明白为什么我不能unz()
直接使用readRDS()
:
iris3 <- readRDS(unz("datasets.zip", "iris.rds"))
这给了我错误:
Error: unknown input format
我也想了解为什么会这样。我知道我可以执行以下操作,如this question:
path <- unzip("datasets.zip", "iris.rds")
iris4 <- readRDS(path)
file.remove(path)
但这似乎并不高效,而且我需要经常为大量文件执行此操作,因此I / O效率低下很重要。是否有任何解决方法来读取rds文件而不将其提取到磁盘?
答案 0 :(得分:8)
在我阅读readRDS()
的正文之前,这有点棘手。你似乎需要做的是
.zip
unz()
存档及其中文件的连接
gzcon()
readRDS()
。以下是一个示例,用于说明在zip存档中使用以下序列化矩阵mat
matrix.zip
mat <- matrix(1:9, ncol = 3)
saveRDS(mat, "matrix.rds")
zip("matrix.zip", "matrix.rds")
打开与matrix.zip
con <- unz("matrix.zip", filename = "matrix.rds")
现在,使用gzcon()
,将GZIP解压缩应用于此连接
con2 <- gzcon(con)
最后,从连接中读取
mat2 <- readRDS(con2)
完全我们有
con <- unz("matrix.zip", filename = "matrix.rds")
con2 <- gzcon(con)
mat2 <- readRDS(con2)
close(con2)
这给出了
> con <- unz("matrix.zip", filename = "matrix.rds")
> con2 <- gzcon(con)
> mat2 <- readRDS(con2)
> close(con2)
> mat2
[,1] [,2] [,3]
[1,] 1 4 7
[2,] 2 5 8
[3,] 3 6 9
> all.equal(mat, mat2)
[1] TRUE
为什么你必须经历这个复杂的额外步骤(我认为)在?readRDS
中描述:
压缩由
file
为a时打开的连接处理 文件名,只有当file
是连接时才可以 由连接处理。所以例如需要url
个连接 被打包到gzcon
。
如果你看一下readRDS()
的内部,我们就会看到:
> readRDS
function (file, refhook = NULL)
{
if (is.character(file)) {
con <- gzfile(file, "rb")
on.exit(close(con))
}
else if (inherits(file, "connection"))
con <- file
else stop("bad 'file' argument")
.Internal(unserializeFromConn(con, refhook))
}
<bytecode: 0x2841998>
<environment: namespace:base>
如果file
是文件名的字符串,则使用gzile()
解压缩对象,以创建与我们要读取的.rds
的连接。请注意,如果您按照file
的方式传递连接,则R在任何时候都不会对连接进行解压缩。 file
刚刚分配到con
,然后传递给内部函数unserializeFromConn
。因此,在gzcon()
创建的连接周围包裹unz
。
基本上,当unserializeFromConn
从连接读取时,它期望它被解压缩,但是当您传递readRDS()
文件名而不是连接时,解压缩只会自动发生。
答案 1 :(得分:1)
readRDS()
的签名是
saveRDS(object, file = "", ascii = FALSE, version = NULL,
compress = TRUE, refhook = NULL)
但是,令人沮丧的是,readRDS
的签名中没有任何内容。然而,当你阅读readRDS
的文档时,你会得到这个小宝石
## or examine the object via a connection, which will be opened as needed.
con <- gzfile("women.rds")
readRDS(con)
close(con)
以及
## Less convenient ways to restore the object
## which demonstrate compatibility with unserialize()
con <- gzfile("women.rds", "rb")
identical(unserialize(con), women)
close(con)
con <- gzfile("women.rds", "rb")
wm <- readBin(con, "raw", n = 1e4) # size is a guess
close(con)
identical(unserialize(wm), women)
另一件需要考虑的事情是你将在RDS对象上使用压缩的收益。考虑
X <- matrix(rnorm(1e7), ncol=10)
saveRDS(X, file = "X.rds")
system("cp X.rds XZ.rds")
system("gzip XZ.rds")
uncomp <- file.info("X.rds")$size
comp <- file.info("XZ.rds.gz")$size
savings <- (1 - comp/uncomp)
# [1] -0.00030541
所以,对于一个非典型的例子,压缩RDS对象会耗费我们的空间。