从压缩文件和已知起始位置(字节偏移量)读取 R 中的二进制文件
Read binary files in R from a zipped file and a known starting position (byte offset)
我在 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 是压缩文件的路径,file_in_zip 是压缩文件中的文件名要读取的文件和 byte_chunk 我要读取的字节数。
在我的用例中,readBin 操作是循环的一部分并逐渐读取整个二进制文件。然而,我很少想阅读所有内容,而且我常常准确地知道我想阅读哪些部分。不幸的是,readBin 没有 start/skip 参数来跳过前 n 个字节。因此,我尝试有条件地用 seek() 替换 readBin() 以跳过不需要的部分的实际读取。
当我尝试这个时,出现错误:
> 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)
到目前为止,我还没有找到解决这个错误的方法。类似的问题可以在这里找到(遗憾的是没有满意的答案):
- https://stat.ethz.ch/pipermail/r-help/2007-December/148847.html(无人接听)
- http://r.789695.n4.nabble.com/reading-file-in-zip-archive-td4631853.html(无答案,但可重现示例)
互联网上的提示建议将 open = 'r' 参数添加到 unz() 或完全删除 open 参数,但这仅适用于非二进制文件(因为默认值为 'r')。人们也建议先解压文件,但由于文件很大,这实际上是不可能的。
是否有任何变通方法可以在二进制压缩文件中查找或使用字节偏移量读取(可能通过 Rcpp 包使用 C++)?
更新:
进一步的研究似乎表明在 zip 文件中 seek() 不是一个简单的问题。 This question suggests a c++ library that can at best use a coarse seek. This Python question 表示由于 zip 的实现方式,完全不可能进行精确查找(尽管它与粗查找方法并不矛盾)。
这里有一些技巧可能对您有用。这是一个伪造的二进制文件:
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
此方法将处理存储二进制数据大小的"expense"偏移到shell/pipe,out of R.
这适用于 win10,R-3.3.2。我正在使用 Git for Windows 中的 dd
(版本 2.11.0.3,尽管 2.11.1 可用),以及 RTools 中的 unzip
和 sh
。
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"
我在 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 是压缩文件的路径,file_in_zip 是压缩文件中的文件名要读取的文件和 byte_chunk 我要读取的字节数。
在我的用例中,readBin 操作是循环的一部分并逐渐读取整个二进制文件。然而,我很少想阅读所有内容,而且我常常准确地知道我想阅读哪些部分。不幸的是,readBin 没有 start/skip 参数来跳过前 n 个字节。因此,我尝试有条件地用 seek() 替换 readBin() 以跳过不需要的部分的实际读取。
当我尝试这个时,出现错误:
> 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)
到目前为止,我还没有找到解决这个错误的方法。类似的问题可以在这里找到(遗憾的是没有满意的答案):
- https://stat.ethz.ch/pipermail/r-help/2007-December/148847.html(无人接听)
- http://r.789695.n4.nabble.com/reading-file-in-zip-archive-td4631853.html(无答案,但可重现示例)
互联网上的提示建议将 open = 'r' 参数添加到 unz() 或完全删除 open 参数,但这仅适用于非二进制文件(因为默认值为 'r')。人们也建议先解压文件,但由于文件很大,这实际上是不可能的。
是否有任何变通方法可以在二进制压缩文件中查找或使用字节偏移量读取(可能通过 Rcpp 包使用 C++)?
更新:
进一步的研究似乎表明在 zip 文件中 seek() 不是一个简单的问题。 This question suggests a c++ library that can at best use a coarse seek. This Python question 表示由于 zip 的实现方式,完全不可能进行精确查找(尽管它与粗查找方法并不矛盾)。
这里有一些技巧可能对您有用。这是一个伪造的二进制文件:
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
此方法将处理存储二进制数据大小的"expense"偏移到shell/pipe,out of R.
这适用于 win10,R-3.3.2。我正在使用 Git for Windows 中的 dd
(版本 2.11.0.3,尽管 2.11.1 可用),以及 RTools 中的 unzip
和 sh
。
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"