在Python中将二进制整数或字符串写入文件

12

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

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


澄清:

我的字符串类似于:

binary_string = "001011010110000010010"

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

5个回答

12

要写出一个字符串,你可以使用文件的.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'

但也许处理所有这些 int 的最佳方式是为文件中的二进制字符串决定固定宽度,然后进行转换,如下所示:

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

这不是我想要的。我编辑了问题以更具体地显示我需要做什么。 - KFox
@KFox,你的意思是想要一个函数:给定一个0和1的intstr,你想将其作为整数的二进制表示而不是0/1字符的字符串写入文件。我不确定你所说的“当我只需要3个”的意思是什么。你是指在最大值中只使用了24位吗? - Ryan Haining
抱歉,之前表达得不太清楚。不过我已经找到答案了。还是谢谢你的回复。 - KFox

8
好的,经过更多的搜索,我找到了一个答案。我相信你们其他人可能只是没理解(这也可能是我的错,因为我编辑了两次才让它清晰)。我在这里找到了答案:这里
答案是将每个数据分割成小块,将它们转换为二进制整数,然后放入二进制数组中。之后,您可以使用数组的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)

4

我希望将这个由一串0和1组成的模式写入文件。

如果你想将一个字符串中的比特流写入文件,你需要用类似这样的方式...

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编码变得更长。在Python 3中可以通过使用to_bytes来避免这种情况。 - gngdb

2
简单示例:

例:

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]

0

每次向array.array中添加3位仍会为每个值产生8位。将011010110添加到数组并写入磁盘将产生以下输出:00000011 00000010 00000110。请注意其中的所有填充零。

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

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

                                        ^^ ^ (注意额外的位数)
    

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接