2012-01-24 38 views
23

Tôi cần tự động hóa R để đọc tệp dữ liệu csv vào tệp zip.Tự động đọc tập tin dạng zip trong R

Ví dụ, tôi sẽ gõ:

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

Và trong nội bộ, những gì sẽ được thực hiện là:

  • Unzip myfile.zip vào một thư mục tạm thời
  • Đọc file chỉ chứa trên đó sử dụng read.csv

Nếu có nhiều hơn một tập tin vào tập tin zip, một lỗi được ném.

Vấn đề của tôi là lấy tên của tệp chứa trong tệp zip, được nhúng vào để cung cấp tệp đó làm lệnh read.csv. Có ai biết làm thế nào để làm điều đó?

CẬP NHẬT

Dưới đây là các chức năng tôi đã viết dựa trên @ Paul trả lời:

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

Vì tôi sẽ làm việc với các tập tin hơn bên trong tempdir(), tôi đã tạo ra một thư mục mới bên trong nó, vì vậy tôi không bị lẫn lộn với các tập tin. Tôi hy vọng nó có thể hữu ích!

+0

các bản sao có thể có? tại: http://stackoverflow.com/questions/3053833/using-r-to-download-zipped-data-file-extract-and-import-data; http://stackoverflow.com/questions/7044808/using-r-to-download-gzipped-data-file-extract-and-import-data/7045059#7045059 – aatrujillob

+0

Trên thực tế, liên kết đầu tiên không liên quan, vì sự cố của tôi là không không giải nén tệp, nhưng để lấy tên của các tệp bên trong mã zip. Nhưng có, thứ hai cho thấy lệnh 'list.files', đó là (cho đến nay) mà tôi không biết. –

+0

@jdanielnd: bạn có thể lấy tên tệp trong tệp zip bằng cách sử dụng 'unzip (tệp, danh sách = TRUE)', như tôi đã sử dụng trong câu trả lời của mình. –

Trả lời

9

Bạn có thể sử dụng unzip để giải nén tệp. Tôi chỉ đề cập đến điều này vì nó không phải là rõ ràng từ câu hỏi của bạn cho dù bạn biết điều đó. Về việc đọc tệp. Sau khi trích xuất tệp của bạn sang một thư mục tạm thời (?tempdir), chỉ cần sử dụng list.files để tìm các tệp được đặt vào thư mục tạm thời. Trong trường hợp của bạn, đây chỉ là một tệp, tệp bạn cần. Đọc nó bằng cách sử read.csv là sau đó khá đơn giản:

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

giả định vị trí tempdir của bạn được lưu trữ trong temp_path.

+0

Đó chỉ là những gì tôi đang tìm kiếm! Tôi đã cố gắng sử dụng 'hệ thống (" ls ")' nhưng nó không trả về một đối tượng R - giống như một vectơ. Cảm ơn! –

+0

@ JoãoDaniel 'hệ thống (" ls ")' không phải là cách để đi ở đây nhưng 'hệ thống (" ls ", intern = TRUE)' có lẽ là những gì bạn đã hy vọng cho – Dason

11

Một giải pháp sử dụng 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)), ...) 
} 
2

Nếu bạn đã zcat được cài đặt trên hệ thống của bạn (đó là trường hợp cho Linux, macos, và Cygwin), bạn cũng có thể sử dụng:

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

này giải pháp cũng có lợi thế là không có tệp tạm thời nào được tạo.

4

Tôi đã tìm thấy chuỗi này vì tôi đã cố gắng tự động đọc nhiều tệp csv từ một tệp zip. Tôi đã điều chỉnh giải pháp cho trường hợp rộng hơn. Tôi đã không thử nghiệm nó cho tên tập tin lạ hoặc như thế, nhưng đây là những gì làm việc cho tôi vì vậy tôi nghĩ rằng tôi muốn chia sẻ:

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

Tôi đã phải sử dụng 'đệ quy = TRUE' trong 'list.files()'; Ngoài ra, thay vì sử dụng 'grep()' để tập hợp con trong định nghĩa thứ hai của 'tệp', bạn có thể đơn giản sử dụng đối số' pattern' trong 'list.files':' files <- list.files (zipdir, đệ quy = TRUE, pattern = "\\. Csv $" '. Tôi cũng đã thực hiện cải tiến đặt tên cho danh sách được trả về,' tên (csv.data) <- gsub (". + \\ /", "", tệp, perl = T) 'Tôi có thể thêm những thay đổi này như là một câu trả lời mới, nhưng cảm thấy tự do để cập nhật cách tiếp cận của bạn Cảm ơn! – rbatt

+1

@ rbatt Phản hồi tuyệt vời. Tôi vẫn còn mới với R khi tôi viết điều đó vì vậy tôi không biết để tìm kiếm các tùy chọn như 'pattern' và' đệ quy'. Tôi nghi ngờ tôi sẽ chỉnh sửa câu trả lời của mình nhưng tôi rất thích xem mã của bạn. –

1

Sau đây là các câu trả lời sau. FUN có thể là read.csv, cat hoặc bất cứ thứ gì bạn thích, cung cấp đối số đầu tiên sẽ chấp nhận đường dẫn tệp. Ví dụ.

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

Tôi vừa viết chức năng dựa trên read.zip hàng đầu có thể giúp ...

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

Đây là phương pháp tôi đang sử dụng dựa trên @Corned Beef Hash Map 'answer. Dưới đây là một số thay đổi tôi đã thực hiện:

  • Tiếp cận của tôi làm cho việc sử dụng data.table gói của fread(), mà có thể được nhanh chóng (thường, nếu nó được nén, kích thước có thể lớn, vì vậy bạn đứng để đạt được một rất nhiều tốc độ ở đây!).

  • Tôi cũng đã điều chỉnh định dạng đầu ra sao cho nó là danh sách được đặt tên, trong đó mỗi phần tử của danh sách được đặt tên theo tệp. Đối với tôi, đây là một sự bổ sung rất hữu ích cho .

  • Thay vì sử dụng biểu thức thông thường để sàng lọc thông qua các tập tin nắm lấy bởi list.files, tôi tận dụng list.file() 's pattern tranh cãi.

  • Cuối cùng, tôi bằng cách dựa vào fread() và bằng cách làm pattern một cuộc tranh cãi mà bạn có thể cung cấp một cái gì đó giống như "" hoặc NULL hoặc ".", bạn có thể sử dụng nó để đọc trong nhiều loại tập tin dữ liệu; trên thực tế, bạn có thể đọc trong nhiều loại cùng một lúc (nếu .zip của bạn chứa .csv, .txt trong bạn muốn cả hai, ví dụ:). Nếu chỉ có một số loại tệp bạn muốn, bạn cũng có thể chỉ định mẫu để chỉ sử dụng các tệp đó.

Dưới đây là chức năng thực tế:

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

Một cách tiếp cận sử dụng fread từ gói 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 
    ... 
) 
} 

Dựa trên câu trả lời/cập nhật bởi @ João-daniel