2017-01-30 44 views
10

我在Windows操作系统下有一个压缩的二进制文件,我试图用R读取。到目前为止,它使用unz()函数结合readBin()函数。从压缩文件和已知起始位置读取R中的二进制文件(字节偏移量)

> 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没有启动/跳过参数来跳过前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) 

到目前为止,我没有找到一个方法来解决这个错误。类似的问题都可以在这里找到(可惜没有一个满意的答案):

提示所有在互联网上建议增加打开='r'参数到unz()或完全放弃open参数,但只适用于非二进制文件(因为默认值为'r')。人们还建议首先解压缩文件,但由于文件相当大,这实际上是不可能的。

是否有任何解决方法寻找二进制压缩文件或读取字节偏移量(可能使用C++通过Rcpp包)?

更新

进一步的研究似乎表明,寻求()在zip文件不是一个简单的问题。 建议一个C++库,最多可以使用粗略搜索。 This Python question表示由于zip的实现方式(尽管它与粗略搜索方法不矛盾),精确查找是完全不可能的。

+0

在'seek'的文档中,它表示不鼓励在Windows上使用seek,所以要警告。只是一个奇怪的问题:这个文件是如何创建的?你有控制它是如何创建的? – chinsoon12

+0

你是否愿意考虑其他语言?这似乎是像C/C++/Java这样的语言的问题。看到这个http://www.phillipciske.com/blog/index.cfm/2008/10/2/Reading-Binary-Files-in-a-Zip-File-Before-CF8 – chinsoon12

+0

@ chinsoon12,该错误的起源是可疑的,因为在这里提到:http://stackoverflow.com/questions/32736845/is-seek-reliable-on-modern-windows/32737017你的第二个问题的答案是否定的。我不创建该文件,因为它是由第三方工具创建的。 – takje

回答

7

这里有一点可能适合你的破解。这里有一个假的二进制文件:

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 

该方法将处理存储二进制数据大小的“开销”抵消到shell/pipe上,从R中移除。

这对win10,R-3.3.2有效。我使用Git for Windows(版本2.11.0.3,尽管2.11.1可用)的dd,以及来自RTools的unzipsh

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" 
+1

非常优雅的解决方案。我做了一些测试,似乎这个解决方案并没有将整个解压缩文件保存在内存中。它需要一些CPU时间来解压缩,直到偏移量,但我想这是真的没有办法。一个进一步的改进是在达到偏移+计数结束时立即停止解压缩。你有什么想法如何做到这一点? – takje

+0

不,这是问题的一部分:我认为你使用'unzip'的最好的解决方案是“每个文件”。 – r2evans

+0

您是否被迫使用'zip'压缩门,或者您是否允许使用其他协议/工具重新压缩? – r2evans

相关问题