2017-01-30 105 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