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

Использование внутренней встроенной функции tar для определенных файлов

R имеет удобную кросс-платформенную функцию tar(), которая может использовать tar и gzip файлы. Кажется, эта функция была разработана для определения всех каталогов. Я надеялся использовать эту функцию для tar и сжать подмножество каталога или один файл. Однако я не могу этого сделать. Я ожидал, что следующее будет загружать один файл csv в текущем рабочем каталоге:

tar( "tst.tgz", "myCsv.csv", compression="gzip" )

Так можно ли использовать только функцию tar() в каталогах?

Я временно обошел это, создав каталог temp, скопировав мои файлы, а затем перезагрузив весь файл temp. Но я надеялся на более простое решение. Это не потребует копирования файлов, которые занимают много времени для больших файлов.

4b9b3361

Ответ 1

Я не думаю, что это возможно, поскольку вы описываете JD. Аргумент files передается аргументу path list.files, и в результате он работает путем дефрагментации файлов в каталогах, а не отдельных файлов.

Если вы готовы отредактировать внутреннюю функцию, tar() можно сделать, чтобы сделать то, что вы хотите, путем вызова вызова list.files() внутри tar(). Немного возился с функцией tar2() ниже, которая содержит дополнительные аргументы, чтобы контролировать, что возвращает list.files(). Используя эту функцию, мы можем добиться того, чего вы хотите, используя такой вызов:

tar2("foo.tar", path = ".", pattern = "bar.csv", recursive = FALSE, 
     full.names = FALSE, all.files = FALSE)

all.files = FALSE, вероятно, избыточен, если у вас нет скрытых файлов с именами, содержащими "bar.csv".

Бит recursive = FALSE просто останавливает поиск функции в любом месте, кроме текущего каталога, который кажется вам нужным и ускоряет поиск, если рабочий каталог содержит много файлов и подпапок.

Бит full.names = FALSE является ключевым. Если это, если TRUE, list.files() возвращает совпадающее имя файла как "./bar.csv", которое tar() будет вставляться в папку внутри tarball. Если мы установим это на FALSE, list.files() возвращает "bar.csv", поэтому мы получаем tarball с одним CSV файлом в соответствии с запросом.

Если у вас есть файлы с похожими именами и вы хотите найти только указанное имя файла, привяжите его к шаблону с помощью ^ и $, например:

tar2("foo.tar", path = ".", pattern = "^bar.csv$", recursive = FALSE, 
     full.names = FALSE, all.files = FALSE)

Здесь приведена измененная функция tar() как tar2():

tar2 <- function (tarfile, files = NULL, compression = c("none", "gzip", 
    "bzip2", "xz"), compression_level = 6, tar = Sys.getenv("tar"),
    pattern = NULL, all.files = TRUE, recursive = TRUE, full.names = TRUE) 
{
    if (is.character(tarfile)) {
        TAR <- tar
        if (nzchar(TAR) && TAR != "internal") {
            flags <- switch(match.arg(compression), none = "cf", 
                gzip = "zcf", bzip2 = "jcf", xz = "Jcf")
            cmd <- paste(TAR, flags, shQuote(tarfile), paste(shQuote(files), 
                collapse = " "))
            return(invisible(system(cmd)))
        }
        con <- switch(match.arg(compression), none = file(tarfile, 
            "wb"), gzip = gzfile(tarfile, "wb", compress = compression_level), 
            bzip2 = bzfile(tarfile, "wb", compress = compression_level), 
            xz = xzfile(tarfile, "wb", compress = compression_level))
        on.exit(close(con))
    }
    else if (inherits(tarfile, "connection")) 
        con <- tarfile
    else stop("'tarfile' must be a character string or a connection")
    files <- list.files(files, recursive = recursive, all.files = all.files, 
        full.names = full.names, pattern = pattern)
    bf <- unique(dirname(files))
    files <- c(bf[!bf %in% c(".", files)], files)
    for (f in unique(files)) {
        info <- file.info(f)
        if (is.na(info$size)) {
            warning(gettextf("file '%s' not found", f), domain = NA)
            next
        }
        header <- raw(512L)
        if (info$isdir && !grepl("/$", f)) 
            f <- paste(f, "/", sep = "")
        name <- charToRaw(f)
        if (length(name) > 100L) {
            if (length(name) > 255L) 
                stop("file path is too long")
            s <- max(which(name[1:155] == charToRaw("/")))
            if (is.infinite(s) || s + 100 < length(name)) 
                stop("file path is too long")
            warning("storing paths of more than 100 bytes is not portable:\n  ", 
                sQuote(f), domain = NA)
            prefix <- name[1:(s - 1)]
            name <- name[-(1:s)]
            header[345 + seq_along(prefix)] <- prefix
        }
        header[seq_along(name)] <- name
        header[101:107] <- charToRaw(sprintf("%07o", info$mode))
        uid <- info$uid
        if (!is.null(uid) && !is.na(uid)) 
            header[109:115] <- charToRaw(sprintf("%07o", uid))
        gid <- info$gid
        if (!is.null(gid) && !is.na(gid)) 
            header[117:123] <- charToRaw(sprintf("%07o", gid))
        size <- ifelse(info$isdir, 0, info$size)
        header[137:147] <- charToRaw(sprintf("%011o", as.integer(info$mtime)))
        if (info$isdir) 
            header[157L] <- charToRaw("5")
        else {
            lnk <- Sys.readlink(f)
            if (is.na(lnk)) 
                lnk <- ""
            header[157L] <- charToRaw(ifelse(nzchar(lnk), "2", 
                "0"))
            if (nzchar(lnk)) {
                if (length(lnk) > 100L) 
                  stop("linked path is too long")
                header[157L + seq_len(nchar(lnk))] <- charToRaw(lnk)
                size <- 0
            }
        }
        header[125:135] <- charToRaw(sprintf("%011o", as.integer(size)))
        header[258:262] <- charToRaw("ustar")
        header[264:265] <- charToRaw("0")
        s <- info$uname
        if (!is.null(s) && !is.na(s)) {
            ns <- nchar(s, "b")
            header[265L + (1:ns)] <- charToRaw(s)
        }
        s <- info$grname
        if (!is.null(s) && !is.na(s)) {
            ns <- nchar(s, "b")
            header[297L + (1:ns)] <- charToRaw(s)
        }
        header[149:156] <- charToRaw(" ")
        checksum <- sum(as.integer(header))%%2^24
        header[149:154] <- charToRaw(sprintf("%06o", as.integer(checksum)))
        header[155L] <- as.raw(0L)
        writeBin(header, con)
        if (info$isdir || nzchar(lnk)) 
            next
        inf <- file(f, "rb")
        for (i in seq_len(ceiling(info$size/512L))) {
            block <- readBin(inf, "raw", 512L)
            writeBin(block, con)
            if ((n <- length(block)) < 512L) 
                writeBin(raw(512L - n), con)
        }
        close(inf)
    }
    block <- raw(512L)
    writeBin(block, con)
    writeBin(block, con)
    invisible(0L)
}

Ответ 2

Это было пересмотрено, еще раз упростив код tar1. Кроме того, tar1 теперь может выводить один файл без каталога или нескольких файлов без каталога. По существу нам нужно обойти ошибку при использовании list.files по R в tar, и мы делаем это, переопределяя list.files, который использует tar1.

Строка, которая управляет средой tar, фактически создает копию tar, среда которой является средой внутри tar1, поэтому при запуске скопированного tar она сначала ищет там list.files. Если бы мы не сделали копию tar с новой средой, тогда она использовала бы list.files в базе R, игнорируя наше переопределение.

Ниже tar1 представляет собой вариацию команды tar, которая создает файл tar, компоненты которого имеют один уровень (т.е. один файл или набор файлов без каталогов). Предполагается, что все файлы находятся в текущем каталоге.

Следуя определению tar1, мы тестируем его, создавая два файла и создавая архив с первым из этих файлов, а затем с обоими этими файлами.

# tar a single file
tar1 <- function(...) {
    list.files <- function(...) ..1
    environment(tar) <- environment()
    tar(...)
}

# test - first create test files, then some test runs of tar1
cat("a", file = "a.csv")
cat("b", file = "a.csv")

tar1("tst.tgz", "a.csv", "gzip")
tar1("tst2.tgz", Sys.glob("*.csv"), "gzip")

Ответ 3

Что произойдет, если вы дадите files= вектор символов, который он запрашивает, скажем, запустив list.files() (или его синоним dir()) с подходящим шаблоном? Кажется, там помогает помощь:

Аргументы:

tarfile: путь к расширению tarfile: тильда (см.           'Path.expand). В качестве альтернативы,           соединение, которое может использоваться для двоичной записи.

files: Символьный вектор offilepaths для архивирования: по умолчанию           заключается в архивировании всех файлов в текущем каталоге.