Подтвердить что ты не робот

Автоматизировать чтение 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 внутри него, поэтому я не путаюсь с файлами. Надеюсь, это будет полезно!

4b9b3361

Ответ 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)