【问题标题】:Writing bits to a binary file将位写入二进制文件
【发布时间】:2014-01-19 18:37:05
【问题描述】:

我有 23 位表示为一个字符串,我需要将此字符串作为 4 个字节写入二进制文件。最后一个字节始终为 0。以下代码有效(Python 3.3),但感觉不是很优雅(我对 Python 和编程还比较陌生)。你有什么让它变得更好的秘诀吗?似乎 for 循环可能很有用,但我如何在循环中进行切片而不得到 IndexError?请注意,当我将位提取到一个字节中时,我颠倒了位顺序。

from array import array

bin_array = array("B")
bits = "10111111111111111011110"    #Example string. It's always 23 bits
byte1 = bits[:8][::-1]
byte2 = bits[8:16][::-1]
byte3 = bits[16:][::-1]
bin_array.append(int(byte1, 2))
bin_array.append(int(byte2, 2))
bin_array.append(int(byte3, 2))
bin_array.append(0)

with open("test.bnr", "wb") as f:
    f.write(bytes(bin_array))

# Writes [253, 255, 61, 0] to the file

【问题讨论】:

    标签: python python-3.x


    【解决方案1】:

    你可以把它当作一个int,然后创建4个字节如下:

    >>> bits = "10111111111111111011110"
    >>> int(bits[::-1], 2).to_bytes(4, 'little')
    b'\xfd\xff=\x00'
    

    【讨论】:

    • @Jon 那真是……太棒了。有可能走另一条路吗?类似:int.from_bytes(b'\xfd\xff=\x00', 'little') 并获取 "10111111111111111011110"
    • @Olav,是的 - 适当地格式化它:format(int.from_bytes(b'\xfd\xff=\x00', 'little'), '023b')[::-1]
    • 这个问题在这个网站上被问了很多次,但这是所有答案中唯一合理的解决方案,谢谢
    • @YungGun: int.to_bytes() 直到 3.2 版才添加到 Python 中,因此为了与使用 struct 模块的当前和旧版本的语言兼容,如 my answer 所示,可能更可取,因为它适用于 Python 2.x 和 3.x。
    • @Kebman 不是真的...见en.wikipedia.org/wiki/…
    【解决方案2】:

    struct 模块正是为这类事情而设计的——考虑以下内容,其中将字节转换分解为一些不必要的中间步骤,以便更清楚地理解它:

    import struct
    
    bits = "10111111111111111011110"  # example string. It's always 23 bits
    int_value = int(bits[::-1], base=2)
    bin_array = struct.pack('i', int_value)
    with open("test.bnr", "wb") as f:
        f.write(bin_array)
    

    一种更难阅读但更短的方法是:

    bits = "10111111111111111011110"  # example string. It's always 23 bits
    with open("test.bnr", "wb") as f:
        f.write(struct.pack('i', int(bits[::-1], 2)))
    

    【讨论】:

      【解决方案3】:
      from array import array
      
      bin_array = array("B")
      bits = "10111111111111111011110"
      
      bits = bits + "0" * (32 - len(bits))  # Align bits to 32, i.e. add "0" to tail
      for index in range(0, 32, 8):
          byte = bits[index:index + 8][::-1]
          bin_array.append(int(byte, 2))
      
      with open("test.bnr", "wb") as f:
          f.write(bytes(bin_array))
      

      【讨论】:

        【解决方案4】:

        您可以使用re.findall方法在一行中执行拆分:

        >>>bits = "10111111111111111011110"
        >>>import re
        >>>re.findall(r'\d{1,8}', bits)
        ['10111111', '11111111', '1011110']
        

        作为一种算法,您可以将bits 填充到长度为32,然后使用re.findall 方法将其分组为八位字节:

        >>> bits
        '10111111111111111011110000000000'
        >>> re.findall(r'\d{8}', bits)
        ['10111111', '11111111', '10111100', '00000000']
        

        你的代码应该是这样的:

        import re
        from array import array
        
        bin_array = array("B")
        bits = "10111111111111111011110".ljust(32, '0')  # pad it to length 32
        
        for octect in re.findall(r'\d{8}', bits): # split it in 4 octects
            bin_array.append(int(octect[::-1], 2)) # reverse them and append it
        
        with open("test.bnr", "wb") as f:
            f.write(bytes(bin_array))
        

        【讨论】:

        • 填充将更明确为bits = "10111111111111111011110".ljust(32, '0')
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-06-07
        • 2012-04-20
        • 2020-10-30
        • 1970-01-01
        相关资源
        最近更新 更多