Запись двоичного целого числа или строки в файл в python

у меня есть строка (это может быть целое число) в Python, и я хочу записать ее в файл. Он содержит только нули и единицы я хочу, чтобы картина нулей и единиц, которые будут записаны в файл. Я хочу написать двоичный файл напрямую, потому что мне нужно хранить много данных, но только определенные значения. Я не вижу необходимости занимать пространство использования восьми бит на значение, когда мне нужно только три.

например. Предположим, я должен был написать двоичную строку "01100010" в файл. Если я его открыл в текстовый редактор он сказал бы b (01100010 код ascii для b). Не смущает. Я не хочу писать коды ascii, пример должен был просто указать, что я хочу напрямую записывать байты в файл.


пояснение:

моя строка выглядит так:

binary_string = "001011010110000010010"

Он не состоит из двоичных кодов для чисел или символов. Он содержит данные, относящиеся только к моей программе.

5 ответов


чтобы написать строку, вы можете использовать .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 функция вместо того, чтобы превратить его в строку 0s и 1s

>>> 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'

Я хочу, чтобы этот шаблон единиц и нулей был записан в файл.

если вы хотите написать битовый поток из строки в файл, вам понадобится что-то вроде этого...

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                             -`.

хорошо, после довольно много поисков, я нашел ответ. Я считаю, что остальные из вас просто не поняли (что, вероятно, было моей ошибкой, так как мне пришлось дважды редактировать, чтобы прояснить это). Я нашел его здесь.

ответ состоял в том, чтобы разделить каждую часть данных, преобразовать их в двоичное целое число, а затем поместить их в двоичный массив. После этого вы можете использовать массив 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))

f = file('binary.mydata','wb')
bin_array.tofile(f)
f.close()

пример:

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]

добавляя к array.array 3 бит будет по-прежнему производить 8 бит для каждого значения. Добавление 011, 010 и 110 к массиву и записи на диск будет производить следующий вывод: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

содержимое байта.дат:

  • hex:2D 60 12
  • binary (на 8 бит):00101101 01100000 00010010
  • двоичный (на 3 бита):001 011 010 110 000 000 010 010

                                        ^^ ^ (Note extra bits)
    

    обратите внимание, что этот метод будет заполнять последние значения, чтобы он выравнивался по 8-битной границе, а заполнение идет к наиболее значительным битам (левая сторона последнего байта в приведенном выше выводе). Поэтому вам нужно быть осторожным и, возможно, добавить нули в конец исходной строки, чтобы сделать длину строки кратной 8.