我需要自动化R来读取一个zip文件中的csv数据文件。
例如,我会输入:
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()
内的更多文件,我在其中创建了一个新的目录,所以我不会对这些文件感到困惑。我希望它可能有用!
答案 0 :(得分: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)), ...)
}
答案 1 :(得分:10)
您可以使用unzip
解压缩文件。我只是提到这一点,因为你的问题不清楚你是否知道这一点。关于阅读文件。将文件解压缩到临时目录(?tempdir
)后,只需使用list.files
查找转储到临时目录中的文件。在您的情况下,这只是一个文件,您需要的文件。然后使用read.csv
阅读它非常简单:
l = list.files(temp_path)
read.csv(l[1])
假设您的tempdir
位置存储在temp_path
。
答案 2 :(得分:4)
我找到了这个帖子,因为我试图自动从zip中读取多个csv文件。我将解决方案改编为更广泛的案例。我没有测试它是否有奇怪的文件名之类,但这对我有用,所以我想我会分享:
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)}
答案 3 :(得分:2)
如果您的系统上安装了zcat(Linux,macos和cygwin就是这种情况),您也可以使用:
zipfile<-"test.zip"
myData <- read.delim(pipe(paste("zcat", zipfile)))
此解决方案还具有不会创建临时文件的优势。
答案 4 :(得分:2)
这是我使用的一种方法,它主要基于@Corned Beef Hash Map&#39; s answer。以下是我所做的一些更改:
我的方法是使用data.table
包fread()
,
可以很快(通常,如果它是拉链的,尺寸可能很大,所以你
站在这里获得很大的速度!)。
我还调整了输出格式,使其成为命名列表,其中 列表的每个元素都以文件命名。对我来说,这是一个 非常有用的补充。
而不是使用正则表达式来筛选文件
抓住list.files,我使用了list.file()
&#39; s pattern
参数。
最后,我依靠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)
}
答案 5 :(得分:1)
以下内容改进了上述答案。 FUN可以是read.csv,cat或任何你喜欢的东西,只要第一个参数接受文件路径。 E.g。
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(...)))
}
答案 6 :(得分:1)
另一种使用data.table包
中的fread
的方法
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的答案/更新
答案 7 :(得分: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, ...)
}
答案 8 :(得分:0)
outDir<-"~/Documents/unzipFolder"
zipF <- list.files(path = "~/Documents/", pattern = "*.zip", full.names = TRUE)
purrr::map(.x = zipF, .f = unzip, exdir = outDir)