2010-07-10 200 views
13

我正在閱讀二進制文件(本例中爲jpg),並且需要在該文件中查找一些值。對於那些有興趣的人來說,二進制文件是一個JPG文件,我試圖通過尋找二進制結構detailed here來挑選它的尺寸。Python:搜索/讀取二進制數據

我需要在二進制數據中找到FFC0,向前跳過一些字節數,然後讀取4個字節(這應該給我圖像尺寸)。

什麼是在二進制數據中搜索值的好方法?有沒有相當於'找到',或類似的東西?

+1

你有沒有看過imagick? IIRC還有一個Python庫。 – txwikinger 2010-07-10 00:44:16

+0

我有,而且效果很好,但是找到文件的尺寸很重。 – Parand 2010-07-10 00:50:03

+1

你應該使用適合類似這樣的模塊http://snippets.dzone.com/posts/show/1021 – 2010-07-10 02:31:52

回答

7

實際上,您可以將文件加載到字符串中,然後使用str.find()方法在字符序列0xffc0中搜索該字符串。它適用於任何字節序列。

執行此操作的代碼取決於幾件事情。如果以二進制模式打開文件並且使用Python 3(這兩種方法可能是此場景的最佳實踐),則需要搜索字節字符串(而不是字符串),這意味着您必須在字符串前添加b

with open(filename, 'rb') as f: 
    s = f.read() 
s.find(b'\xff\xc0') 

如果您打開在Python 3文本模式下的文件,你必須搜索字符串:

with open(filename, 'r') as f: 
    s = f.read() 
s.find('\xff\xc0') 

雖然沒有特別的理由這樣做。如果您使用的平臺對待二進制文件和文本文件的方式不同(例如Windows),那麼這會導致問題。

Python 2沒有區分字節字符串和字符串,所以如果您使用的是該版本,則無論您是在b'\xff\xc0'中包含還是排除b。如果您的平臺以相同方式處理二進制文件和文本文件(例如Mac或Linux),則使用'r'還是'rb'作爲文件模式也無關緊要。但我仍然推薦使用類似上面第一個代碼示例的東西來提供前向兼容性 - 如果您曾經切換到Python 3,那麼這是一個不太需要解決的問題。

+6

如果它是一個非常大的文件,那麼將它一次讀入一個字符串並不是一個好主意。 – icktoofay 2010-07-10 00:51:13

+2

我懷疑這是如此之大,這將是一個問題。 – 2010-07-10 00:52:07

+3

因爲我只是在尋找第一幀,所以我可能會讀取文件的一小部分,然後處理它而不是讀取整個文件。 – Parand 2010-07-10 00:55:46

4

re模塊確實與兩個字符串和二進制數據(str在Python 2和bytes在Python 3)工作,所以你可以爲你的任務中使用它,以及str.find

2

好吧,顯然有PIL圖像模塊的大小作爲一個屬性。如果你想得到你想要的大小,並且不加載文件,你將不得不逐行通過它。不是最好的方式,但它會工作。

6

bitstring模塊專爲此目的而設計。對於你的情況下,下面的代碼(我沒有測試)應該幫助說明:

from bitstring import ConstBitStream 
# Can initialise from files, bytes, etc. 
s = ConstBitStream(filename='your_file') 
# Search to Start of Frame 0 code on byte boundary 
found = s.find('0xffc0', bytealigned=True) 
if found: 
    print("Found start code at byte offset %d." % found[0]) 
    s0f0, length, bitdepth, height, width = s.readlist('hex:16, uint:16, 
                 uint:8, 2*uint:16') 
    print("Width %d, Height %d" % (width, height)) 
+0

因此'Bits.find'只返回一個布爾值並設置'Bits.bytepos'屬性?也許在模塊文檔中,你應該警告'bitstring'不是線程安全的(當然這不是重要的)。 – tzot 2010-07-11 09:08:27

+0

@ΤΖΩΤΖΙΟΥ:是的,你有一個好點。我不覺得突變的方法或讀取方法不是線程安全的,但是可以合理預期使用位於不可變對象上的「查找」。說實話,它從來沒有出現過,但它是一件值得思考的事情... – 2010-07-12 07:08:39

+0

只是一個想法:'find'可以返回一個包含所有必要信息的對象,包括''''''''''''''。爲了向後兼容,您可以將此「BitMatch」類作爲「bool」的子類。 – tzot 2010-07-12 07:33:03

1

而不是整個文件讀入內存,搜索它,然後寫一個新的文件到磁盤可以使用MMAP爲此模塊。 mmap將而不是將整個文件存儲在內存中,並允許就地修改。

#!/usr/bin/python 

import mmap 

with open("hugefile", "rw+b") as f: 
    mm = mmap.mmap(f.fileno(), 0) 
    print mm.find('\x00\x09\x03\x03') 
0

蟒> = 3.2

import re 

f = open("filename.jpg", "rb") 
byte = f.read() 
f.close() 

matchObj = re.match(b'\xff\xd8.*\xff\xc0...(..)(..).*\xff\xd9', byte, re.MULTILINE|re.DOTALL) 
if matchObj: 
    # http://stackoverflow.com/questions/444591/convert-a-string-of-bytes-into-an-int-python 
    print (int.from_bytes(matchObj.group(1), 'big')) # height 
    print (int.from_bytes(matchObj.group(2), 'big')) # width 
1

find()方法應該僅當你需要知道子的位置,如果沒有,則可以使用in運算符,例如可以使用:

with open("foo.bin", 'rb') as f: 
    if b'\x00' in f.read(): 
     print('The file is binary!') 
    else: 
     print('The file is not binary!') 
+1

這對我來說 - 我試圖比較一個字符串字節字符串。我所要做的就是把b放在我的搜索字詞前面,它在字節字符串中找到。 – pa1983 2016-08-18 10:01:34

0

在Python 3.x中,你可以通過另一個字節的字符串,這樣搜索的字節字符串:

>>> byte_array = b'this is a byte array\r\n\r\nXYZ\x80\x04\x95 \x00\x00\x00\x00\x00' 
>>> byte_array.find('\r\n\r\n'.encode()) 
20 
>>>