Запись булевой строки в двоичный файл?

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

# first append the string with 0s to make its length a multiple of 8 while len(boolString) % 8 != 0: boolString += '0' # write the string to the file byte by byte i = 0 while i < len(boolString) / 8: byte = int(boolString[i*8 : (i+1)*8], 2) outputFile.write('%c' % byte) i += 1 

Но это генерирует выходной 1 байт за раз и работает медленно. Что было бы более эффективным способом сделать это?

Это должно быть быстрее, если вы сначала вычислите все свои байты, а затем напишите их все вместе. Например

 b = bytearray([int(boolString[x:x+8], 2) for x in range(0, len(boolString), 8)]) outputFile.write(b) 

Я также использую bytearray который является естественным контейнером для использования, а также может быть записан непосредственно в ваш файл.


Конечно, вы можете использовать библиотеки, если это подходит, например bitarray и bitstring . Используя последнее, вы можете просто сказать

 bitstring.Bits(bin=boolString).tofile(outputFile) 

Вот еще один ответ, на этот раз с использованием служебной утилиты Industrial-strength от PyCrypto – The Python Cryptography Toolkit, где в версии 2.6 (последняя последняя стабильная версия) она определена в pycrypto-2.6/lib/Crypto/Util/number.py ,

Комментарии, предшествующие этому, говорят:
Improved conversion functions contributed by Barry Warsaw, after careful benchmarking

 import struct def long_to_bytes(n, blocksize=0): """long_to_bytes(n:long, blocksize:int) : string Convert a long integer to a byte string. If optional blocksize is given and greater than zero, pad the front of the byte string with binary zeros so that the length is a multiple of blocksize. """ # after much testing, this algorithm was deemed to be the fastest s = b('') n = long(n) pack = struct.pack while n > 0: s = pack('>I', n & 0xffffffffL) + s n = n >> 32 # strip off leading zeros for i in range(len(s)): if s[i] != b('\000')[0]: break else: # only happens when n == 0 s = b('\000') i = 0 s = s[i:] # add back some pad bytes. this could be done more efficiently wrt the # de-padding being done above, but sigh... if blocksize > 0 and len(s) % blocksize: s = (blocksize - len(s) % blocksize) * b('\000') + s return s 

Вы можете преобразовать булевскую строку в long используя data = long(boolString,2) . Затем, чтобы записать это долго на диск, вы можете использовать:

 while data > 0: data, byte = divmod(data, 0xff) file.write('%c' % byte) 

Однако нет необходимости создавать логическую строку. Гораздо проще использовать long . long тип может содержать бесконечное количество бит. Используя бит-манипуляцию, вы можете установить или очистить бит по мере необходимости. Затем вы можете записать длинный диск в целом в одну операцию записи.

Вы можете попробовать этот код, используя класс массива :

 import array buffer = array.array('B') i = 0 while i < len(boolString) / 8: byte = int(boolString[i*8 : (i+1)*8], 2) buffer.append(byte) i += 1 f = file(filename, 'wb') buffer.tofile(f) f.close() 

Класс-помощник (показано ниже) упрощает:

 class BitWriter: def __init__(self, f): self.acc = 0 self.bcount = 0 self.out = f def __del__(self): self.flush() def writebit(self, bit): if self.bcount == 8 : self.flush() if bit > 0: self.acc |= (1 << (7-self.bcount)) self.bcount += 1 def writebits(self, bits, n): while n > 0: self.writebit( bits & (1 << (n-1)) ) n -= 1 def flush(self): self.out.write(chr(self.acc)) self.acc = 0 self.bcount = 0 with open('outputFile', 'wb') as f: bw = BitWriter(f) bw.writebits(int(boolString,2), len(boolString)) bw.flush() 

Используйте пакет struct .

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

Редактировать:

Пример использования ? как символ формата для bool .

 import struct p = struct.pack('????', True, False, True, False) assert p == '\x01\x00\x01\x00' with open("out", "wb") as o: o.write(p) 

Давайте посмотрим на файл:

 $ ls -l out -rw-r--r-- 1 lutz lutz 4 Okt 1 13:26 out $ od out 0000000 000001 000001 000000 

Прочтите его снова:

 with open("out", "rb") as i: q = struct.unpack('????', i.read()) assert q == (True, False, True, False)