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!
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
.
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)), ...)
}
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)}
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éé.
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()
'spattern
argument. -
enfin, I en s'appuyant sur
fread()
et en faisantpattern
un argument auquel vous pourriez fournir quelque chose comme""
ouNULL
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)
}
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(...)))
}
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
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, ...)
}