如何在python中将任意长度的位串写入二进制文件

时间:2019-08-19 08:09:39

标签: python binary byte binaryfiles

我需要写一个位串,它不一定总是二进制文件的8的倍数。我还需要再次从文件中成功读取字符串。

字符串的开头永远不会为0。 字符串示例:

bitstring = '10110101111111001101101010011011111010011010110001010101011100010110100010001001110001110100011111010001100011011110010100110000010111101011001011010111111100000110000000001001101000010110000111'

我需要使用尽可能少的存储空间。因此,如果字符串的长度为194(以上),则我需要文件大小为194 // 8 + 1 = 25个字节,尽管我不确定是否可以在bin文件中存储非整数字节。

这是我第一次使用二进制文件,请原谅不良做法。

这是我当前写入文件的解决方案:

with open(filename,"wb+") as f:
    f.write(bytes(list(map(int, bitstring))))
    f.close()

要读取的内容:

string = "".join(list(map(str,np.fromfile(filename,"u1"))))

使用EmEditor,字符串中的每个数字都存储为2位数的二进制字符串,这是不希望的。我意识到这可能是因为我将位串拆分为单个数字。这是二进制编辑器中显示的上述位串:

01 00 01 01 00 01 00 01  01 01 01 01 01 01 00 00  01 01 00 01 01 00 01 00  01 00 00 01 01 00 01 01 
01 01 01 00 01 00 00 01  01 00 01 00 01 01 00 00  00 01 00 01 00 01 00 01  00 01 01 01 00 00 00 01 
00 01 01 00 01 00 00 00  01 00 00 00 01 00 00 01  01 01 00 00 00 01 01 01  00 01 00 00 00 01 01 01 
01 01 00 01 00 00 00 01  01 00 00 00 01 01 00 01  01 01 01 00 00 01 00 01  00 00 01 01 00 00 00 00 
00 01 00 01 01 01 01 00  01 00 01 01 00 00 01 00  01 01 00 01 00 01 01 01  01 01 01 01 00 00 00 00 
00 01 01 00 00 00 00 00  00 00 00 00 01 00 00 01  01 00 01 00 00 00 00 01  00 01 01 00 00 00 00 01 
01 01 

(所有数字均为2位数字,文件大小为194字节,这是文件/字符串中二进制数字的数量)

我试图使用具有相同结果的字节数组

非常感谢

3 个答案:

答案 0 :(得分:0)

可以通过将字符串转换为整数并将二进制整数写入文件来解决此问题

import os
from array import *

def main():
    filename = "test.bin"
    bitstring = '10110101111111001101101010011011111010011010110001010101011100010110100010001001110001110100011111010001100011011110010100110000010111101011001011010111111100000110000000001001101000010110000111'
    print(bitstring)

    # split string to 8 bites long chunks
    splits = [bitstring[x:x + 8] for x in range(0, len(bitstring), 8)]
    print(splits)

    bin_array_in = array('B')
    bin_array_out = array('B')

    # convert bits to int and add to list
    for split in splits:
        bin_array_in.append(int(split, 2))

    print(bin_array_in)

    # dump list to file
    with open(filename, "wb+") as f:
        bin_array_in.tofile(f)
        f.close()

    print("file size: {}".format(os.path.getsize(filename)))

    # get the list from file
    with open(filename, "rb+") as f:
        bin_array_out.fromfile(f, len(bin_array_in))
        f.close()

    print(bin_array_out)

    # convert back to bin and join to one string 
    bitstring = ""
    for i in bin_array_out:
        bitstring += "{:08b}".format(i, "08b")

    print(bitstring)


if __name__ == '__main__':
    main()

只有一个问题,最后一个字节填充0以形成8位块。 不知道是不是更容易更改读/写逻辑或使您的初始字符串为% 8,所以我让您弄清楚这部分。

答案 1 :(得分:0)

尝试一下:

>>> bitstring = '10110101111111001101101010011011111010011010110001010101011100010110100010001001110001110100011111010001100011011110010100110000010111101011001011010111111100000110000000001001101000010110000111'
>>> a = int(bitstring, 2)
>>> a
17849302729865679414224788101014796653923247039249910236551L
>>> bin(a)[2:] == bitstring
True

将位串转换为整数后,可以按通常方式将其写入文件。然后读回来。然后转换回位串(参见上文)并获得原始的。

答案 2 :(得分:0)

向hiro主角建议使用位数组,因为这是我能做的最简单的实现(无法将注释标记为答案)。感谢答案,但使用位数组我可以用最少的代码行来解决它。 / p>

以下是解决方案: 写:

bitstring = "11010101001101010011101"
bitarr = bitarray([0 for _ in range(8-(len(bitstring)%8))] + list(map(int,bitstring)))

with open(filename,"wb+") as f:
    bitarr.tofile(f)

阅读:

with open(filename, "rb") as f:
string = "".join(_reformat_bin(list(map(str,np.fromfile(string,"u1")))))

while not int(string[0]):
    string = string[1:]

_reformat_bin()将代表数字0-255的字符串数组转换为代表字节的字符串arr,例如

>>> _reformat_bin(["255", "0", "9"])
>>> ["11111111", "00000000", "00001001"]

全力以赴。