Автоматизируйте чтение zip-файлов в R - PullRequest
24 голосов
/ 24 января 2012

Мне нужно автоматизировать R для чтения файла данных csv, который находится в zip-файле.

Например, я бы набрал:

read.zip(file = "myfile.zip")

И внутренне, что бы было сделано, это:

  • Распаковать myfile.zip во временную папку
  • Прочитать единственный файл, содержащийся в нем, используя read.csv

Если в zip-файле содержится более одного файла, выдается ошибка.

Моя проблема заключается в том, чтобы получить имя файла, содержащегося в zip-файле, в том порядке, в котором он указан, для выполнения команды read.csv. Кто-нибудь знает, как это сделать?

UPDATE

Вот функция, которую я написал на основе ответа @Paul:

read.zip <- function(zipfile, row.names=NULL, dec=".") {
    # Create a name for the dir where we'll unzip
    zipdir <- tempfile()
    # Create the dir using that name
    dir.create(zipdir)
    # Unzip the file into the dir
    unzip(zipfile, exdir=zipdir)
    # Get the files into the dir
    files <- list.files(zipdir)
    # Throw an error if there's more than one
    if(length(files)>1) stop("More than one data file inside zip")
    # Get the full name of the file
    file <- paste(zipdir, files[1], sep="/")
    # Read the file
    read.csv(file, row.names, dec)
}

Так как я буду работать с большим количеством файлов внутри tempdir(), я создал новый каталог внутри него, так что я не путаюсь с файлами. Я надеюсь, что это может быть полезно!

Ответы [ 9 ]

11 голосов
/ 24 января 2012

Другое решение с использованием unz:

read.zip <- function(file, ...) {
  zipFileInfo <- unzip(file, list=TRUE)
  if(nrow(zipFileInfo) > 1)
    stop("More than one data file inside zip")
  else
    read.csv(unz(file, as.character(zipFileInfo$Name)), ...)
}
10 голосов
/ 24 января 2012

Вы можете использовать unzip, чтобы распаковать файл. Я просто упоминаю об этом, поскольку из вашего вопроса не ясно, знали ли вы это. Что касается чтения файла. После того, как вы извлекли файл во временный каталог (?tempdir), просто используйте list.files, чтобы найти файлы, которые были выгружены во временный каталог. В вашем случае это всего лишь один файл, файл, который вам нужен. Прочитать его, используя read.csv, довольно просто:

l = list.files(temp_path)
read.csv(l[1])

при условии, что ваше местоположение tempdir хранится в temp_path.

4 голосов
/ 07 сентября 2013

Я нашел эту ветку, когда пытался автоматизировать чтение нескольких файлов CSV из zip.Я адаптировал решение для более широкого случая.Я не проверял его на странные имена файлов или тому подобное, но это то, что сработало для меня, поэтому я решил поделиться:

read.csv.zip <- function(zipfile, ...) {
# Create a name for the dir where we'll unzip
zipdir <- tempfile()
# Create the dir using that name
dir.create(zipdir)
# Unzip the file into the dir
unzip(zipfile, exdir=zipdir)
# Get a list of csv files in the dir
files <- list.files(zipdir)
files <- files[grep("\\.csv$", files)]
# Create a list of the imported csv files
csv.data <- sapply(files, function(f) {
    fp <- file.path(zipdir, f)
    return(read.csv(fp, ...))
})
return(csv.data)}
2 голосов
/ 05 августа 2015

Вот подход, который я использую, который в значительной степени основан на answer @Corned Beef Hash Map.Вот некоторые из изменений, которые я сделал:

  • Мой подход использует data.table пакет *1007*, который может быть быстрым (как правило, если он упакован, размеры могут быть большимитак что вы стоите, чтобы набрать здесь большую скорость!).

  • Я также настроил формат вывода так, чтобы он был именованным списком, где каждый элемент списка назван в честь файла.Для меня это было очень полезным дополнением.

  • Вместо использования регулярных выражений для просмотра файлов, захваченных list.files, я использую list.file() patternАргумент.

  • Наконец, я, опираясь на fread() и сделав pattern аргумент, для которого вы можете указать что-то вроде "" или NULL или ".",Вы можете использовать это для чтения во многих типах файлов данных;на самом деле, вы можете читать сразу несколько типов (если ваш .zip содержит .csv, вы хотите, например, оба .txt).Если вам нужны только некоторые типы файлов, вы также можете указать шаблон для их использования.

Вот фактическая функция:

read.csv.zip <- function(zipfile, pattern="\\.csv$", ...){

    # Create a name for the dir where we'll unzip
    zipdir <- tempfile()

    # Create the dir using that name
    dir.create(zipdir)

    # Unzip the file into the dir
    unzip(zipfile, exdir=zipdir)

    # Get a list of csv files in the dir
    files <- list.files(zipdir, rec=TRUE, pattern=pattern)

    # Create a list of the imported csv files
    csv.data <- sapply(files, 
        function(f){
            fp <- file.path(zipdir, f)
            dat <- fread(fp, ...)
            return(dat)
        }
    )

    # Use csv names to name list elements
    names(csv.data) <- basename(files)

    # Return data
    return(csv.data)
}
2 голосов
/ 10 апреля 2013

Если в вашей системе установлен zcat (как в случае с linux, macos и cygwin), вы также можете использовать:

zipfile<-"test.zip"
myData <- read.delim(pipe(paste("zcat", zipfile)))

Преимущество этого решения в том, что временные файлы не создаются.

1 голос
/ 20 ноября 2015

Другой подход, использующий fread из пакета data.table

fread.zip <- function(zipfile, ...) {
  # Function reads data from a zipped csv file
  # Uses fread from the data.table package

  ## Create the temporary directory or flush CSVs if it exists already
  if (!file.exists(tempdir())) {dir.create(tempdir())
  } else {file.remove(list.files(tempdir(), full = T, pattern = "*.csv"))
  }

  ## Unzip the file into the dir
  unzip(zipfile, exdir=tempdir())

  ## Get path to file
  file <- list.files(tempdir(), pattern = "*.csv", full.names = T)

  ## Throw an error if there's more than one
  if(length(file)>1) stop("More than one data file inside zip")

  ## Read the file
  fread(file, 
     na.strings = c(""), # read empty strings as NA
     ...
  )
}

На основе ответа / обновления @ joão-daniel

1 голос
/ 05 июля 2014

Следующее уточняет приведенные выше ответы.FUN может быть read.csv, cat или чем угодно, при условии, что первый аргумент примет путь к файлу.Например,

head(read.zip.url("http://www.cms.gov/Medicare/Coding/ICD9ProviderDiagnosticCodes/Downloads/ICD-9-CM-v32-master-descriptions.zip", filename = "CMS32_DESC_LONG_DX.txt"))

read.zip.url <- function(url, filename = NULL, FUN = readLines, ...) {
  zipfile <- tempfile()
  download.file(url = url, destfile = zipfile, quiet = TRUE)
  zipdir <- tempfile()
  dir.create(zipdir)
  unzip(zipfile, exdir = zipdir) # files="" so extract all
  files <- list.files(zipdir)
  if (is.null(filename)) {
    if (length(files) == 1) {
      filename <- files
    } else {
      stop("multiple files in zip, but no filename specified: ", paste(files, collapse = ", "))
    }
  } else { # filename specified
    stopifnot(length(filename) ==1)
    stopifnot(filename %in% files)
  }
  file <- paste(zipdir, files[1], sep="/")
  do.call(FUN, args = c(list(file.path(zipdir, filename)), list(...)))
}
0 голосов
/ 18 июня 2019

расположение разархивированного файла

outDir<-"~/Documents/unzipFolder"

получить все ZIP-файлы

zipF <- list.files(path = "~/Documents/", pattern = "*.zip", full.names = TRUE)

распакуйте все ваши файлы

purrr::map(.x = zipF, .f = unzip, exdir = outDir)

0 голосов
/ 25 июня 2015

Я только что написал функцию, основанную на top read.zip, которая может помочь ...

read.zip <- function(zipfile, internalfile=NA, read.function=read.delim, verbose=TRUE, ...) {
    # function based on /7839541/avtomatiziruite-chtenie-zip-failov-v-r

    # check the files within zip
    unzfiles <- unzip(zipfile, list=TRUE)
    if (is.na(internalfile) || is.numeric(internalfile)) {
        internalfile <- unzfiles$Name[ifelse(is.na(internalfile),1,internalfile[1])]
    }
    # Create a name for the dir where we'll unzip
    zipdir <- tempfile()
    # Create the dir using that name
    if (verbose) catf("Directory created:",zipdir,"\n")
    dir.create(zipdir)
    # Unzip the file into the dir
    if (verbose) catf("Unzipping file:",internalfile,"...")
    unzip(zipfile, file=internalfile, exdir=zipdir)
    if (verbose) catf("Done!\n")
    # Get the full name of the file
    file <- paste(zipdir, internalfile, sep="/")
    if (verbose) 
        on.exit({ 
            catf("Done!\nRemoving temporal files:",file,".\n") 
            file.remove(file)
            file.remove(zipdir)
            }) 
    else
        on.exit({file.remove(file); file.remove(zipdir);})
    # Read the file
    if (verbose) catf("Reading File...")
    read.function(file, ...)
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...