Автоматизация чтения zip-файла в R

Мне нужно автоматизировать R, чтобы читать csv файл данных в zip-архиве.

Например, я бы набрал:

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

24
задан Jack Wasey 6 October 2015 в 10:08
поделиться

6 ответов

Вы можете использовать unzip, чтобы распаковать файл. Я просто упоминаю об этом, поскольку из вашего вопроса не ясно, знали ли вы это. Что касается чтения файла. После того, как вы извлекли файл во временный каталог (?tempdir), просто используйте list.files, чтобы найти файлы, которые были выгружены во временный каталог. В вашем случае это всего лишь один файл, файл, который вам нужен. Считать его с помощью read.csv тогда довольно просто:

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

при условии, что ваше tempdir местоположение сохранено в temp_path.

10
ответ дан 29 November 2019 в 00:01
поделиться

Следующее уточняет приведенные выше ответы. 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(...)))
}
1
ответ дан 29 November 2019 в 00:01
поделиться

Вот подход, который я использую, который в значительной степени основан на ответе @Corned Beef Hash Map . Вот некоторые из изменений, которые я сделал:

  • Мой подход использует пакет data.table fread(), который может быть быстрым (обычно, если он заархивирован, размеры могут быть большими Таким образом, вы стоите, чтобы набрать большую скорость здесь!).

  • Я также настроил выходной формат так, чтобы он был именованным списком, где каждый элемент списка назван в честь файла. Для меня это было очень полезным дополнением.

  • Вместо использования регулярных выражений для просмотра файлов, захваченных list.files, я использую аргумент list.file() 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)
}
2
ответ дан 29 November 2019 в 00:01
поделиться

Если у вас установлен zcat в вашей системе (как в случае с linux, macos и cygwin), вы также можете использовать:

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

Преимущество этого решения в том, что временные файлы не создаются .

2
ответ дан 29 November 2019 в 00:01
поделиться

Другой подход, использующий 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'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

1
ответ дан 29 November 2019 в 00:01
поделиться

Я только что написал функцию на основе 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, ...)
}
0
ответ дан 29 November 2019 в 00:01
поделиться
Другие вопросы по тегам:

Похожие вопросы: