Автоматизировать чтение zip файла в R
Мне нужно автоматизировать R, чтобы прочитать файл данных csv, который находится в zip файле.
Например, я бы напечатал:
read.zip(file = "myfile.zip")
И внутренне, что будет сделано:
- Разархивировать
myfile.zip
во временную папку
- Прочитайте единственный файл, содержащийся на нем, с помощью
read.csv
Если в zip файл находится более одного файла, возникает ошибка.
Моя проблема заключается в том, чтобы получить имя файла, содержащегося в zip файле, в orded, чтобы предоставить ему команду 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 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()
, я создал новый dir внутри него, поэтому я не путаюсь с файлами. Надеюсь, это будет полезно!
Ответы
Ответ 1
Вы можете использовать unzip
для распаковки файла. Я просто упоминаю об этом, поскольку из вашего вопроса неясно, знаете ли вы это. Что касается чтения файла. После того, как вы извлекли файл во временный каталог (?tempdir
), просто используйте list.files
, чтобы найти файлы, которые были сброшены во временный каталог. В вашем случае это всего лишь один файл, нужный вам файл. Чтение его с помощью read.csv
довольно просто:
l = list.files(temp_path)
read.csv(l[1])
если ваше местоположение tempdir
хранится в temp_path
.
Ответ 2
Другое решение, использующее 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)), ...)
}
Ответ 3
Я нашел эту ветку, когда пытался автоматизировать чтение нескольких файлов 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)}
Ответ 4
Если у вас установлена zcat в вашей системе (это относится к linux, macos и cygwin), вы также можете использовать:
zipfile<-"test.zip"
myData <- read.delim(pipe(paste("zcat", zipfile)))
Это решение также имеет то преимущество, что временные файлы не создаются.
Ответ 5
Вот такой подход, который я использую, который основан на @Corned Beef Hash Map answer. Вот некоторые из изменений, которые я сделал:
-
В моем подходе используется пакет data.table
fread()
, который
может быть быстрым (обычно, если он застегнут, размеры могут быть большими, так что вы
стоять, чтобы получить много скорости здесь!).
-
Я также скорректировал выходной формат, чтобы он был именованным списком, где
каждый элемент списка имеет имя после файла. Для меня это было
очень полезное дополнение.
-
Вместо использования регулярных выражений для просеивания файлов
grabbed by list.files, я использую list.file()
pattern
аргумент.
-
Наконец, я полагаясь на fread()
и делая pattern
an
аргумент, на который вы могли бы поставить что-то вроде ""
или 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)
}
Ответ 6
Следующее уточняет приведенные выше ответы. 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(...)))
}
Ответ 7
Другой подход, который использует 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 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
Ответ 8
Я просто написал функцию, основанную на верхнем 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, ...)
}
Ответ 9
разархивированное местоположение файла
outDir<-"~/Documents/unzipFolder"
получить все почтовые файлы
zipF <- list.files(path = "~/Documents/", pattern = "*.zip", full.names = TRUE)
распакуйте все ваши файлы
purrr::map(.x = zipF,.f = unzip, exdir = outDir)