是否有原因我无法直接从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文件而不将其提取到磁盘中?

最佳答案

在我阅读readRDS()的正文之前,要跟踪它有点棘手。看来您需要做的是

  • 使用.zip打开到unz()存档及其内部文件的连接
  • 使用gzcon()
  • 将GZIP减压应用于此连接
  • 最后将这个解压缩的连接传递给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中描述为什么要经历这个复杂的额外步骤:



    如果您查看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()传递给文件名而不是连接时,解压缩才会自动发生。

    关于r - 在不解压缩到磁盘的情况下读取zip文件中的RDS文件,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/33289973/

    10-12 00:35
    查看更多