r decompression

Automatizar la lectura de archivos zip en R



decompression (8)

Acabo de escribir una función basada en top read.zip que puede ayudar ...

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, ...) }

Necesito automatizar R para leer un archivo de datos csv que esté en un archivo zip.

Por ejemplo, yo escribiría:

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

E internamente, lo que se haría es:

  • Descomprima myfile.zip en una carpeta temporal
  • Lee el único archivo contenido en él usando read.csv

Si hay más de un archivo en el archivo zip, se produce un error.

Mi problema es obtener el nombre del archivo contenido en el archivo zip, ordenado para proporcionarle el comando read.csv . Alguien sabe como hacerlo?

ACTUALIZAR

Aquí está la función que escribí basada en la respuesta de @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) }

Ya que estaré trabajando con más archivos dentro de tempdir() , creé un nuevo directorio dentro de él, para no confundirme con los archivos. Espero que sea de utilidad!


Encontré este hilo mientras intentaba automatizar la lectura de varios archivos csv desde un archivo zip. Adapté la solución al caso más amplio. No lo he probado para nombres de archivo raros o similares, pero esto es lo que funcionó para mí, así que pensé que lo compartiría:

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)}


Este es un enfoque que estoy usando y que se basa en gran medida en la respuesta de @Corned Beef Hash Map. Aquí están algunos de los cambios que hice:

  • Mi enfoque utiliza el data.table fread() del paquete fread() , que puede ser rápido (por lo general, si está comprimido, los tamaños pueden ser grandes, por lo que puede ganar mucha velocidad aquí).

  • También ajusté el formato de salida para que sea una lista con nombre, donde cada elemento de la lista lleva el nombre del archivo. Para mí, esta fue una adición muy útil.

  • En lugar de usar expresiones regulares para examinar los archivos capturados por list.files, utilizo el argumento de pattern list.file() .

  • Finalmente, confiando en fread() y creando un argumento para el que podría proporcionar algo como "" o NULL o "." , puedes usar esto para leer muchos tipos de archivos de datos; de hecho, puedes leer en varios tipos de a la vez (si tu .zip contiene .csv, .txt en ambos, por ejemplo). Si solo desea algunos tipos de archivos, puede especificar el patrón para que solo los use.

Aquí está la función real:

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) }


Lo siguiente refina las respuestas anteriores. FUN podría ser read.csv, cat, o cualquier cosa que desee, siempre que el primer argumento acepte una ruta de archivo. P.ej

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


Otra solución usando 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)), ...) }


Otro enfoque que utiliza fread del paquete 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 ... ) }

Basado en la respuesta / actualización de @ joão-daniel


Puedes usar unzip para descomprimir el archivo. Solo menciono esto, ya que no queda claro en tu pregunta si lo sabías. En lo que respecta a la lectura del archivo. Una vez que haya extraído el archivo a un directorio temporal ( ?tempdir ), solo use list.files para encontrar los archivos que fueron volcados en el directorio temporal. En su caso, esto es solo un archivo, el archivo que necesita. read.csv usando read.csv es bastante sencillo:

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

asumiendo que su ubicación tempdir se almacena en temp_path .


Si tiene instalado zcat en su sistema (como es el caso de linux, macos y cygwin) también podría usar:

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

Esta solución también tiene la ventaja de que no se crean archivos temporales.