【问题标题】:Write a binary integer or string to a file in python将二进制整数或字符串写入python中的文件
【发布时间】:2013-05-29 01:23:42
【问题描述】:

我在 Python 中有一个字符串(它也可以是一个整数),我想将它写入一个文件。它仅包含 1 和 0 我希望将这种 1 和 0 模式写入文件。我想直接编写二进制文件,因为我需要存储大量数据,但只存储某些值。当我只需要三个时,我认为没有必要占用每个值使用八位的空间。

例如。假设我要将二进制字符串"01100010" 写入文件。如果我在文本编辑器中打开它,它会显示b(01100010 是 b 的 ascii 代码)。不过不要混淆。我不想写ascii代码,这个例子只是为了表明我想直接将字节写入文件。


澄清:

我的字符串看起来像这样:

binary_string = "001011010110000010010"

它不是由数字或字符的二进制代码组成的。它包含仅与我的程序相关的数据。

【问题讨论】:

    标签: python file file-io binary


    【解决方案1】:

    要写出一个字符串,您可以使用文件的.write 方法。要写入整数,您需要使用struct 模块

    import struct
    
    #...
    with open('file.dat', 'wb') as f:
        if isinstance(value, int):
            f.write(struct.pack('i', value)) # write an int
        elif isinstance(value, str):
            f.write(value) # write a string
        else:
            raise TypeError('Can only write str or int')
    

    但是,int 和 string 的表示方式不同,你可以使用 bin 函数将其转换为 0 和 1 的字符串

    >>> bin(7)
    '0b111'
    >>> bin(7)[2:] #cut off the 0b
    '111'
    

    但也许处理所有这些ints 的最佳方法是为文件中的二进制字符串确定一个固定宽度并像这样转换它们:

    >>> x = 7
    >>> '{0:032b}'.format(x) #32 character wide binary number with '0' as filler
    '00000000000000000000000000000111'
    

    【讨论】:

    • 这不是我想要的。我编辑了问题以更具体地显示我需要做什么。
    • @KFox 所以你说你想要一个函数:给定 intstr 的 0 和 1,你想将它作为二进制表示形式写入文件一个 int 而不是 0/1 字符的字符串。我不确定“当我只需要 3 个时”是什么意思。你的意思是你只使用最大值中的 24 位?
    • 对不起,它相当不清楚。反正我现在已经找到答案了。不过感谢您的回复。
    【解决方案2】:

    好吧,经过相当多的搜索,我找到了答案。我相信你们其他人根本不明白(这可能是我的错,因为我不得不编辑两次才能弄清楚)。我找到了here

    答案是将每条数据拆分,将它们转换为二进制整数,然后将它们放入二进制数组中。之后,您可以使用数组的tofile() 方法写入文件。

    from array import *
    
    bin_array = array('B')
    
    bin_array.append(int('011',2))
    bin_array.append(int('010',2))
    bin_array.append(int('110',2))
    
    with file('binary.mydata', 'wb') as f:
        bin_array.tofile(f)
    

    【讨论】:

      【解决方案3】:

      我希望将 1 和 0 的模式写入文件。

      如果您的意思是要将比特流从字符串写入文件,则需要这样的东西...

      from cStringIO import StringIO
      
      s = "001011010110000010010"
      sio = StringIO(s)
      
      f = open('outfile', 'wb')
      
      while 1:
          # Grab the next 8 bits
          b = sio.read(8)
      
          # Bail if we hit EOF
          if not b:
              break
      
          # If we got fewer than 8 bits, pad with zeroes on the right
          if len(b) < 8:
              b = b + '0' * (8 - len(b))
      
          # Convert to int
          i = int(b, 2)
      
          # Convert to char
          c = chr(i)
      
          # Write
          f.write(c)
      
      f.close()
      

      ...xxd -b outfile 显示...

      0000000: 00101101 01100000 10010000                             -`.
      

      【讨论】:

      • 这会在 8 位块以“1”开头时中断,因为 utf-8 编码是 longer。这可以在 Python 3 中避免,using to_bytes
      【解决方案4】:

      简单示例:

      my_number = 1234
      with open('myfile', 'wb') as file_handle:
          file_handle.write(struct.pack('i', my_number))
      ...
      with open('myfile', 'rb') as file_handle:
          my_number_back = struct.unpack('i', file_handle.read())[0]
      

      【讨论】:

        【解决方案5】:

        一次附加到array.array 3 位仍然会为每个值生成 8 位。将011010110 附加到数组并写入磁盘将产生以下输出:00000011 00000010 00000110。注意那里所有的填充零。

        您似乎想将二进制三元组“压缩”成字节以节省空间。鉴于您问题中的示例字符串,您可以将其转换为整数列表(一次 8 位),然后直接将其写入文件。这会将所有位打包在一起,每个值仅使用 3 位而不是 8 位。

        Python 3.4 示例

        original_string = '001011010110000010010'
        
        # first split into 8-bit chunks
        bit_strings = [original_string[i:i + 8] for i in range(0, len(original_string), 8)]
        
        # then convert to integers
        byte_list = [int(b, 2) for b in bit_strings]
        
        with open('byte.dat', 'wb') as f:
            f.write(bytearray(byte_list))  # convert to bytearray before writing
        

        byte.dat 的内容:

        • 十六进制:2D 60 12
        • 二进制(8 位):00101101 01100000 00010010
        • 二进制(3 位):001 011 010 110 000 000 010 010

                                              ^^ ^ (Note extra bits)
          

          请注意,此方法将填充最后一个值,使其与 8 位边界对齐,并且填充到最高有效位(上述输出中最后一个字节的左侧)。所以你需要小心,并可能在原始字符串的末尾添加零以使字符串长度成为 8 的倍数。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2015-07-02
          • 2015-01-30
          • 2016-01-15
          • 2015-05-07
          • 1970-01-01
          • 2020-08-28
          • 1970-01-01
          • 2021-10-27
          相关资源
          最近更新 更多