我正在读取二进制文件(在这种情况下为jpg),并且需要在该文件中找到一些值。对于那些感兴趣的人,二进制文件是一个jpg,我试图通过查找二进制结构detailed here来挑选它的维度。
我需要在二进制数据中找到FFC0,跳过一些字节数,然后读取4个字节(这应该给我图像尺寸)。
在二进制数据中搜索值的好方法是什么?是否有相当于'find'或类似re?
的东西答案 0 :(得分:11)
您实际上可以将文件加载到字符串中,并使用0xffc0
方法搜索该字符串str.find()
的字符串。它适用于任何字节序列。
执行此操作的代码取决于几个方面。如果你以二进制模式打开文件而你正在使用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
中包含或排除b'\xff\xc0'
无关紧要。如果您的平台以相同方式处理二进制文件和文本文件(例如Mac或Linux),那么使用'r'
或'rb'
作为文件模式也无关紧要。但是我仍然建议使用上面第一个代码示例之类的东西,只是为了向前兼容 - 如果你切换到Python 3,那么修复它就少了一点。
答案 1 :(得分: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))
答案 2 :(得分:5)
不是将整个文件读入内存,搜索它然后将新文件写入磁盘,而是可以使用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')
答案 3 :(得分:4)
re
模块支持同时使用字符串和二进制数据(Python 2中的str
和Python 3中的bytes
),所以你可以使用它和str.find
来完成任务。
答案 4 :(得分:2)
嗯,显然有PIL Image模块的大小是一个属性。如果您想要获得建议的大小,并且没有加载文件,您将不得不逐行浏览。不是最好的方法,但它会起作用。
答案 5 :(得分:1)
只有在您需要知道sub的位置时才应使用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!')
答案 6 :(得分:1)
在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
>>>
答案 7 :(得分:0)
对于Python> = 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