Возможно, но я не знаю ни одной чистой реализации (она может существовать). Ниже приведен базовый код R, который должен работать во многих случаях (например, имена файлов с полным путем внутри архива должны быть не более 100 символов). В некотором смысле, это просто повторная реализация «untar» чрезвычайно грубым способом, но таким образом, что он будет указывать на нужный файл в сжатом файле.
Первая проблема заключается в том, что вы должны читать только сжатый файл с самого начала. Использование «seek ()» для повторного позиционирования указателя файла на нужный файл, к сожалению, ошибочно в сжатом файле.
ParseTGZ<- function(archname){
# open tgz archive
tf <- gzfile(archname, open='rb')
on.exit(close(tf))
fnames <- list()
offset <- 0
nfile <- 0
while (TRUE) {
# go to beginning of entry
# never use "seek" to re-locate in a gzipped file!
if (seek(tf) != offset) readBin(tf, what="raw", n= offset - seek(tf))
# read file name
fName <- rawToChar(readBin(tf, what="raw", n=100))
if (nchar(fName)==0) break
nfile <- nfile + 1
fnames <- c(fnames, fName)
attr(fnames[[nfile]], "offset") <- offset+512
# read size, first skip 24 bytes (file permissions etc)
# again, we only use readBin, not seek()
readBin(tf, what="raw", n=24)
# file size is encoded as a length 12 octal string,
# with the last character being '\0' (so 11 actual characters)
sz <- readChar(tf, nchars=11)
# convert string to number of bytes
sz <- sum(as.numeric(strsplit(sz,'')[[1]])*8^(10:0))
attr(fnames[[nfile]], "size") <- sz
# cat(sprintf('entry %s, %i bytes\n', fName, sz))
# go to the next message
# don't forget entry header (=512)
offset <- offset + 512*(ceiling(sz/512) + 1)
}
# return a named list of characters strings with attributes?
names(fnames) <- fnames
return(fnames)
}
Это даст вам точную позицию и длину всех файлов в архиве tar.gz.
Теперь следующий шаг - фактически извлечь единственный файл. Возможно, вы сможете сделать это напрямую, используя соединение gzfile, но здесь я буду использовать rawConnection (). Это предполагает, что ваши файлы помещаются в память.
extractTGZ <- function(archfile, filename) {
# this function returns a raw vector
# containing the desired file
fp <- ParseTGZ(archfile)
offset <- attributes(fp[[filename]])$offset
fsize <- attributes(fp[[filename]])$size
gzf <- gzfile(archfile, open="rb")
on.exit(close(gzf))
# jump to the byte position, don't use seek()
# may be a bad idea on really large archives...
readBin(gzf, what="raw", n=offset)
# now read the data into a raw vector
result <- readBin(gzf, what="raw", n=fsize)
result
}
сейчас, наконец:
ff <- rawConnection(ExtractTGZ("myarchive", "myfile"))
Теперь вы можете обращаться с ff
так, как если бы это был (соединение, указывающее на) ваш файл. Но он существует только в памяти.