Чтение двоичных файлов в R из зашифрованного файла и известной начальной позиции (смещение байта)

У меня есть zipped двоичный файл в операционной системе Windows, который я пытаюсь читать с R. До сих пор он работает с использованием функции unz() в сочетании с функцией readBin().

> bin.con <- unz(zip_path, file_in_zip, open = 'rb')
> readBin(bin.con,
          "double", 
          n = byte_chunk, 
          size = 8L, 
          endian = "little")
> close(bin.con)

Где zip_path - это путь к zip файлу, file_in_zip - это имя файла в zip файле, который должен быть прочитан, и byte_chunk - количество байтов, которое я хочу прочитать.

В моем случае использование операции readBin является частью цикла и постепенно считывает весь двоичный файл. Тем не менее, я редко хочу читать все, и часто я точно знаю, какие части я хочу читать. К сожалению, readBin не имеет аргумента start/skip, чтобы пропустить первые n байтов. Поэтому я попытался условно заменить readBin() на seek(), чтобы пропустить фактическое считывание нежелательных частей.

Когда я пытаюсь это сделать, я получаю сообщение об ошибке:

> bin.con <- unz(zip_path, file_in_zip, open = 'rb')
> seek(bin.con, where = bytes_to_skip, origin = 'current')
Error in seek.connection(bin.con, where = bytes_to_skip, origin = "current") : 
  seek not enabled for this connection
> close(bin.con)

До сих пор я не нашел способа решить эту ошибку. Аналогичные вопросы можно найти здесь (к сожалению, без удовлетворительного ответа):

Советы по всему Интернету позволяют добавить аргумент open = 'r' к unz() или вообще отказаться от открытого аргумента, но это работает только для не двоичных файлов (поскольку по умолчанию это "r" ). Люди также предлагают сначала распаковать файлы, но поскольку файлы довольно большие, это практически невозможно.

Есть ли какая-нибудь работа для поиска в двоичном сжатом файле или чтение со смещением байта (возможно, с помощью С++ через пакет Rcpp)?

Обновление

Дальнейшие исследования показывают, что seek() в zip файлах - непростая задача. Этот вопрос предлагает библиотеку С++, которая в лучшем случае может использовать грубый поиск. Этот вопрос на Python указывает, что точный поиск абсолютно невозможен из-за способа реализации zip (хотя это не противоречит методу грубого поиска).

Ответ 1

Вот немного взлома, который может сработать для вас. Здесь поддельный двоичный файл:

writeBin(as.raw(1:255), "file.bin")
readBin("file.bin", raw(1), n = 16)
#  [1] 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10

И вот полученный zip файл:

zip("file.zip", "file.bin")
#   adding: file.bin (stored 0%)
readBin("file.zip", raw(1), n = 16)
#  [1] 50 4b 03 04 0a 00 02 00 00 00 7b ab 45 4a 87 1f

В этом случае используется временный промежуточный двоичный файл.

system('sh -c "unzip -p file.zip file.bin | dd of=tempfile.bin bs=1c skip=5c count=4c"')
# 4+0 records in
# 4+0 records out
# 4 bytes copied, 0.00044964 s, 8.9 kB/s
file.info("tempfile.bin")$size
# [1] 4
readBin("tempfile.bin", raw(1), n = 16)
# [1] 06 07 08 09

Этот метод компенсирует "расход" на обработку размера хранимых двоичных данных в оболочке/канале из R.

Это работало на win10, R-3.3.2. Я использую dd из Git для Windows (версия 2.11.0.3, хотя доступна 2.11.1) и unzip и sh из RTools.

Sys.which(c("dd", "unzip", "sh"))
#                                    dd 
# "C:\\PROGRA~1\\Git\\usr\\bin\\dd.exe" 
#                                 unzip 
#          "c:\\Rtools\\bin\\unzip.exe" 
#                                    sh 
#             "c:\\Rtools\\bin\\sh.exe"