Lecture automatique de fichiers zip en R

je dois automatiser R pour lire un fichier csv qui est dans un fichier zip.

par exemple, je taperais:

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

et à l'interne, ce qui serait fait est:

  • Décompresser myfile.zip dans un dossier temporaire
  • lire le seul fichier qu'il contient en utilisant read.csv

S'il y a plus d'un fichier dans le fichier zip, une erreur est lancée.

mon problème est d'obtenir le nom du fichier contenu dans le fichier zip, en orded pour lui fournir faire la commande read.csv . Personne ne sait comment le faire?

mise à JOUR

Voici la fonction que j'ai écrite sur la base de la réponse 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)
}

depuis que je vais travailler avec plus de fichiers à l'intérieur du tempdir() , j'ai créé un nouveau dir à l'intérieur, donc je ne me confond pas avec le fichier. J'espère que ça peut être utile!

23
demandé sur Jack Wasey 2012-01-24 16:29:45

8 réponses

Vous pouvez utiliser unzip pour décompresser le fichier. Je le mentionne simplement parce que votre question ne permet pas de savoir si vous le saviez ou non. En ce qui concerne la lecture du fichier. Une fois que vous avez extrait le fichier dans un répertoire temporaire ( ?tempdir ), utilisez list.files pour trouver les fichiers qui ont été stockés dans le répertoire temporaire. Dans votre cas c'est juste un fichier, le fichier dont vous avez besoin. La lecture avec read.csv est alors assez simple:

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

en supposant que votre tempdir est stocké dans temp_path .

9
répondu Paul Hiemstra 2012-01-24 12:49:25

une autre solution utilisant 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)), ...)
}
11
répondu Joshua Ulrich 2012-01-24 14:41:42

j'ai trouvé ce fil alors que j'essayais d'automatiser la lecture de plusieurs fichiers csv à partir d'un zip. J'ai adapté la solution au cas plus large. Je ne l'ai pas testé pour les noms de fichiers bizarres ou autres, mais c'est ce qui a fonctionné pour moi donc j'ai pensé que je partagerais:

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)}
4
répondu Corned Beef Hash Map 2013-09-06 20:20:26

Si vous avez zcat installé sur votre système (ce qui est le cas pour linux, macos, et cygwin), vous pouvez également utiliser:

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

cette solution a aussi l'avantage qu'aucun fichier temporaire n'est créé.

2
répondu Holger Brandl 2013-07-02 15:42:16

Voici une approche que j'utilise qui est fortement basée sur @Corned Beef Hash Map 's answer . Voici quelques-unes des modifications que j'ai apportées:

  • mon approche utilise le paquet data.table 151920920", qui peut être rapide (généralement, si elle est zippée, les tailles peuvent être grandes, donc vous à gagner beaucoup de vitesse ici!).

  • j'ai aussi ajusté le format de sortie de sorte que c'est une liste nommée, où chaque élément de la liste est nommé d'après le fichier. Pour moi, c'était un plus très utile.

  • au lieu d'utiliser des expressions régulières pour passer au crible les fichiers saisi par liste.fichiers, je fais usage de list.file() 's pattern argument.

  • enfin, I en s'appuyant sur fread() et en faisant pattern un argument auquel vous pourriez fournir quelque chose comme "" ou NULL ou "." , vous pouvez l'utiliser pour lire dans de nombreux types de fichiers de données; en fait, vous pouvez lire en plusieurs types de à la fois (si votre .zip contient .csv,.txt, vous voulez à la fois, par exemple). S'il n'y a que quelques types de les fichiers que vous voulez, vous pouvez spécifier le modèle à utiliser seulement ceux, aussi.

Voici la fonction actuelle:

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
répondu rbatt 2017-05-23 10:31:13

ce qui suit précise les réponses ci-dessus. AMUSANT pu être lue.csv, cat, ou tout ce que vous voulez, à condition que le premier argument accepte un chemin de fichier. Par exemple:

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
répondu Jack Wasey 2014-07-05 12:32:25

une autre approche qui utilise fread à partir des données.paquet de 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
     ...
  )
}

basé sur la réponse/mise à jour de @joão-daniel

1
répondu altabq 2015-11-26 21:38:54

je viens d'écrire une fonction basée sur top read.zip qui peuvent vous aider...

read.zip <- function(zipfile, internalfile=NA, read.function=read.delim, verbose=TRUE, ...) {
    # function based on /q/automate-zip-file-reading-in-r-49205/"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, ...)
}
0
répondu Victor Trevino 2015-06-25 17:09:34