Вопрос по r, decompression – Автоматизируйте чтение zip-файлов в R

23

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

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

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

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

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

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

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

ОБНОВИТЬ

Вот функция, которую я написал на основе ответа @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()Я создал новый каталог внутри него, так что я не путаюсь с файлами. Я надеюсь, что это может быть полезно!

возможные дубликаты? в:stackoverflow.com/questions/3053833/...; stackoverflow.com/questions/7044808/... aatrujillob
На самом деле с первой ссылкой это не связано, так как моя проблема не в том, чтобы разархивировать файл, а в том, чтобы получить имя файла внутри почтового индекса. Но да, второй показываетlist.files команда, которая была (пока) неизвестна мной. João Daniel
@jdanielnd: вы можете получить имена файлов в zip-файле, используяunzip(file, list=TRUE), как я использовал в своем ответе. Joshua Ulrich

Ваш Ответ

8   ответов
2

macos и cygwin), вы также можете использовать:

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

Это решение также имеет то преимущество, что временные файлы не создаются.

11

Другое решение с использованием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)), ...)
}
4

когда пытался автоматизировать чтение нескольких файлов 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)}
@rbatt Отличный отзыв. Я все еще был новичком в R, когда писал это, поэтому я не знал, как искать вариантыpattern а такжеrecursive, Я сомневаюсь, что отредактирую свой ответ, но я бы с удовольствием посмотрел ваш код. Спасибо! Corned Beef Hash Map
Я должен был использоватьrecursive=TRUE вlist.files(); Кроме того, вместо использованияgrep() подмножество во втором определенииfiles, вы можете просто использоватьpattern аргумент вlist.files: files <- list.files(zipdir, recursive=TRUE, pattern="\\.csv$", Я также сделал улучшение именования возвращаемого списка,names(csv.data) <- gsub(".+\\/", "", files,perl=T), Я мог бы добавить эти изменения в качестве нового ответа, но не стесняйтесь обновлять свой подход. Спасибо! rbatt
9

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

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

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

@ JoãoDanielsystem("ls") это не путь сюда, ноsystem("ls", intern = TRUE) это то, на что ты надеялся Dason
Это именно то, что я искал! Я пытался использоватьsystem("ls") но он не возвратил объект R - как вектор. Спасибо! João Daniel
2

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

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

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

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

Наконец, я, опираясь на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)
}
0

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

read.zip <- function(zipfile, internalfile=NA, read.function=read.delim, verbose=TRUE, ...) {
    # function based on http://stackoverflow.com/questions/8986818/automate-zip-file-reading-in-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, ...)
}
1

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(...)))
}
1

Другой подход, который использует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

Похожие вопросы