【问题标题】:Turning binary data into a literal string of '0's and '1's将二进制数据转换为 '0' 和 '1' 的文字字符串
【发布时间】:2016-01-01 14:21:37
【问题描述】:

我有一个文件,其中填充了二进制数据,表示大端顺序的 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 字符时它只是打印出十六进制表示。

我从这里去哪里?我需要把我的b'a' 变成'1100001',因为我真正关心的是位,而不是字节。

【问题讨论】:

  • 裸露的try/except 不被认为是好的做法。它可以捕获读取时的 IO 错误或 struct.unpack 或(可能)文件末尾的 struct.error。令人困惑和不好的做法。

标签: python string encoding binary


【解决方案1】:

在 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

【讨论】:

    【解决方案2】:

    您可以将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='')
      
    • 使用裸exceptconsidered 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='')
    

    【讨论】:

    • Python 好得多(比 OP 的函数)!
    • ''.join(map('{:08b}'.format, chunk)) 可以用来代替列表理解。
    猜你喜欢
    • 2017-07-12
    • 1970-01-01
    • 1970-01-01
    • 2017-04-25
    • 1970-01-01
    • 1970-01-01
    • 2013-03-24
    • 1970-01-01
    • 2019-10-10
    相关资源
    最近更新 更多