我有一个文件填充了二进制数据,表示大端序排列的2字节指令序列。
我需要能够将这些指令解码为更有意义的等价物,但我无法将数据转换为可以使用的格式。
我认为最好如果我将指令转换为0和1的实际字符串。
到目前为止,我写过:
def slurpInstructions(filename):
instructions = []
with open(filename, 'rb') as f:
while True:
try:
chunk = f.read(1)
print(struct.unpack('c', chunk))
except:
break
一次打印出1个字节,如下所示:
(b'\x00',)
(b'a',)
我知道文件中的第一条指令是:
0000000001100001
因此,看起来它打印出与每个字节的整数值对应的ascii字符,除了它只是在int值没有ascii char时打印出十六进制表示。
虽然我从哪里出发?我需要将b'a'
转换为'1100001'
,因为我实际上关心的是比特,而不是字节。
答案 0 :(得分:4)
您可以将b'a'
转换为相应的整数ord
值,然后使用'{:b}'.format
以二进制格式打印int:
In [6]: '{:b}'.format(ord(b'a'))
Out[6]: '1100001'
一次一个字节地读取一个大文件可能会非常慢。通过每次调用f.read
读取更多字节,您将获得更好的性能。
您可以使用以下方法以1024字节的块来迭代文件的内容:
with open(filename, 'rb') as f:
for chunk in iter(lambda: f.read(1024), b''):
同样,每个字节调用一次print
可能会非常慢。通过向print
每次调用打印更多字节,您将获得更好的性能。因此,您可以使用列表推导来循环遍历chunk
中的字节,将每个字节转换为字符串二进制格式,然后使用''.join
将字符串连接在一起:
print(''.join(['{:b}'.format(ord(c)) for c in chunk]), end='')
使用裸except
为considered a bad practice。如果您选择在此处使用try..except
,请仅列出您要处理的例外情况:
try:
...
except IOError:
def slurpInstructions(filename):
with open(filename, 'rb') as f:
for chunk in iter(lambda: f.read(1024), b''):
print(''.join(['{:b}'.format(c) for c in chunk]), end='')
答案 1 :(得分:2)
在Python 3中,将2个字节转换为位串('{:b}'.format()
may be slightly slower):
>>> bin(int.from_bytes(b'\x00a', 'big'))[2:].zfill(16)
'0000000001100001'
对于单源Python 2/3兼容版本,请参阅Convert binary to ASCII and vice versa
要加载time- and space-efficiently的所有说明,您可以使用array
module:
#!/usr/bin/env python
import os
import sys
from array import array
instructions = array('H') # each instruction is >=2 bytes
n = os.path.getsize(filename) // instructions.itemsize # number of instructions
with open(filename, 'rb') as file:
instructions.fromfile(file, n) # slurp file
if sys.byteorder == 'little':
instructions.byteswap() # force big-endian order
for h in instructions: # print as bitstrings
print('{:016b}'.format(h))
有关有效阅读二进制文件的其他方法,请参阅Reading binary file in Python and looping over each byte。