2017-02-25 97 views
0

R中的以下代碼返回一個數據幀,其中包含文件名,解包長度(以字節爲單位)和日期(不提取文件)。如何使用R讀取zip壓縮文件中打包文件的大小

unzip(path_to_zip, list = T) 

我想知道如何也可以提取打包(壓縮)文件的大小,或者每個文件的壓縮比。

我正在使用Windows 7機器。

謝謝!

回答

1

使用unzip()函數,您不能:默認情況下,它使用內部C函數來完成它的功能,僅此而已。但是,它可以使用外部可執行文件,並且確實允許允許詳細信息(使用-v)。爲了使用它,你需要修改R的unzip()函數。這個答案的其餘部分是練習「使用,盧克」,表明當前的功能可以在需要時擴展。

unzip2 <- function (zipfile, files = NULL, list = FALSE, list.verbose = FALSE, overwrite = TRUE, 
        junkpaths = FALSE, exdir = ".", unzip = "internal", setTimes = FALSE) { 
    if (identical(unzip, "internal")) { 
     if (!list && !missing(exdir)) 
      dir.create(exdir, showWarnings = FALSE, recursive = TRUE) 
     res <- .External(utils:::C_unzip, zipfile, files, exdir, list, 
      overwrite, junkpaths, setTimes) 
     if (list) { 
      dates <- as.POSIXct(res[[3]], "%Y-%m-%d %H:%M", tz = "UTC") 
      data.frame(Name = res[[1]], Length = res[[2]], Date = dates, 
       stringsAsFactors = FALSE) 
     } 
     else invisible(attr(res, "extracted")) 
    } 
    else { 
     WINDOWS <- .Platform$OS.type == "windows" 
     if (!is.character(unzip) || length(unzip) != 1L || !nzchar(unzip)) 
      stop("'unzip' must be a single character string") 
     zipfile <- path.expand(zipfile) 
     if (list) { 
      dashl <- if (list.verbose) "-lv" else "-l" 
      res <- if (WINDOWS) 
       system2(unzip, c(dashl, shQuote(zipfile)), stdout = TRUE) 
      else system2(unzip, c(dashl, shQuote(zipfile)), stdout = TRUE, 
       env = c("TZ=UTC")) 
      l <- length(res) 
      res2 <- res[-c(1, 3, l - 1, l)] 
      con <- textConnection(res2) 
      on.exit(close(con)) 
      z <- read.table(con, header = TRUE, as.is = TRUE) 
      dt <- paste(z$Date, z$Time) 
      formats <- if (max(nchar(z$Date) > 8)) 
       c("%Y-%m-%d", "%d-%m-%Y", "%m-%d-%Y") 
      else c("%m-%d-%y", "%d-%m-%y", "%y-%m-%d") 
      slash <- any(grepl("/", z$Date)) 
      if (slash) 
       formats <- gsub("-", "/", formats) 
      formats <- paste(formats, "%H:%M") 
      for (f in formats) { 
       zz <- as.POSIXct(dt, tz = "UTC", format = f) 
       if (all(!is.na(zz))) 
        break 
      } 
      z[, "Date"] <- zz 
      z <- z[, colnames(z) != "Time"] 
      nms <- c("Name", "Length", "Date") 
      z[, c(nms, setdiff(colnames(z), nms))] 
     } 
     else { 
      args <- c("-oq", shQuote(zipfile)) 
      if (length(files)) 
       args <- c(args, shQuote(files)) 
      if (exdir != ".") 
       args <- c(args, "-d", shQuote(exdir)) 
      system2(unzip, args, stdout = NULL, stderr = NULL, 
       invisible = TRUE) 
      invisible(NULL) 
     } 
    } 
} 

在此,我修改線:1(參數),6(utils:::),21-25(dashl),45和46-47中加入(列選擇)。其餘的是從原來的R unzip功能。

默認情況下,unzip2的行爲與unzip完全相同,這意味着它不會給你想要的東西。爲了得到您想要的結果,您需要(a)告訴它您的外部unzip.exe位於何處,並且(b)告訴它您希望它是冗長的。 (請隨意修改上述定義以更改默認值。)

請注意,在Windows上,unzip.exe默認情況下通常不會安裝。它包含在Rtools,Git-for-Windowsmsys2中。您可能需要更多努力才能確保Sys.which("unzip")找到可執行文件。

這使用(默認)內部C函數,這意味着沒有更多可以來。

unzip2("~/bashdotfiles.zip", list = TRUE) 
#   Name Length    Date 
# 1 .bash_history 8269 2017-02-20 03:31:00 
# 2 .bash_logout 220 2016-04-22 22:36:00 
# 3  .bashrc 3771 2016-04-22 22:36:00 

它們使用外部可執行文件,並且在功能上是相同的(雖然注意到日期,由於內部UTC轉換是不同的......這可能是固定一點點更多的努力)。

unzip2("~/bashdotfiles.zip", list = TRUE, unzip = Sys.which("unzip")) 
#   Name Length    Date 
# 1 .bash_history 8269 2017-02-20 11:31:00 
# 2 .bash_logout 220 2016-04-23 05:36:00 
# 3  .bashrc 3771 2016-04-23 05:36:00 

最後,增強上市:

unzip2("~/bashdotfiles.zip", list = TRUE, list.verbose = TRUE, unzip = Sys.which("unzip")) 
#   Name Length    Date Method Size Cmpr CRC.32 
# 1 .bash_history 8269 2017-02-20 11:31:00 Defl:N 2717 67% 99c8d736 
# 2 .bash_logout 220 2016-04-23 05:36:00 Defl:N 158 28% 6ce3189b 
# 3  .bashrc 3771 2016-04-23 05:36:00 Defl:N 1740 54% ab254644 
+0

非常感謝詳細的解答!但是,代碼中似乎存在某種錯誤。如果zip文件中的一個文件的文件名中有空格,則代碼將崩潰。例如,我試圖在一個zip文件上運行一個代碼,其中包含一個名爲「a b.pdf」的文件。該代碼返回以下值:502521,b.PDF,Defl:N,,448514,11%,2016-05-18,a'。如果文件名超過1個空格,則代碼崩潰。 – Sasha

+0

這是否發生在'utils :: unzip()'? – r2evans

+0

無論何時使用外部解壓縮可執行文件,這都是'unzip'中的一個錯誤。這個'unzip2'忠實地複製了這種行爲:-)。 – r2evans