Python:读取和写入二进制数据

时间:2013-12-04 10:54:22

标签: python file input binary output

我知道有很多几乎相同的问题,但似乎并非真正针对一般情况。

假设我想打开一个文件,在内存中读取它,可能对相应的bitstring做一些操作并将结果写回文件。

以下对我来说似乎很简单,但它会产生完全不同的输出。请注意,为简单起见,我只在此复制文件:

file = open('INPUT','rb')
data = file.read()
data_16 = data.encode('hex')
data_2 = bin(int(data_16,16))

OUT = open('OUTPUT','wb')

i = 0
while i < len(data_2) / 8:
    byte = int(data_2[i*8 : (i+1)*8], 2)
    OUT.write('%c' % byte)
    i += 1

OUT.close()

我查看了datadata_16data_2。就我所见,转变是有意义的。

正如预期的那样,输出文件的位大小与输入文件的大小完全相同。

编辑:我认为必须削减领先的'0b'的可能性。请参阅以下内容:

>>> data[:100]
'BMFU"\x00\x00\x00\x00\x006\x00\x00\x00(\x00\x00\x00\xe8\x03\x00\x00\xee\x02\x00\x00\x01\x00\x18\x00\x00\x00\x00\x00\x00\x00\x00\x00\x12\x0b\x00\x00\x12\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05=o\xce\xf4^\x16\xe0\x80\x92\x00\x00\x00\x01I\x02\x1d\xb5\x81\xcaN\xcb\xb8\x91\xc3\xc6T\xef\xcb\xe1j\x06\xc3;\x0c*\xb9Q\xbc\xff\xf6\xff\xff\xf7\xed\xdf'
>>> data_16[:100]
'424d46552200000000003600000028000000e8030000ee020000010018000000000000000000120b0000120b000000000000'
>>> data_2[:100]
'0b10000100100110101000110010101010010001000000000000000000000000000000000000000000011011000000000000'
>>> data_2[1]
'b'

也许BMFU"部分应该从data剪切而来?

4 个答案:

答案 0 :(得分:3)

>>> bin(25)
'0b11001'

注意两件事:

  1. 开头的“0b”。这意味着您的切片将偏离2位。

  2. 缺少填充到8位。这会损坏您的数据每次,除非它恰好与第1点相匹配。

  3. 逐字节处理文件,而不是像这样尝试处理它。如果您发现代码太慢,那么您需要找到一种更快的逐字节工作方式,而不是切换到这种无法修复的方法。

答案 1 :(得分:1)

您可以简单地将数据变量写回来,并且您的往返成功。

但看起来您打算将该文件作为01个字符串进行处理。没有错(尽管很少需要),但是你的代码采用了一种非常迂回的方式将数据转换为该形式。而不是构建怪物整数并将其转换为位字符串,而不是一次一个字节:

data = file.read()
data_2 = "".join( bin(ord(c))[2:] for c in data ) 

data_2现在是一系列零和一系列。 (在单个字符串中,与您拥有的相同;但如果您要进行更改,我会将位串保留在列表中)。反向转换也最好逐字节完成:

newdata = "".join(chr(int(byte, 8)) for byte in grouper(long_bitstring, 8, "0"))

这使用itertools documentation中的grouper食谱。

from itertools import izip_longest
def grouper(iterable, n, fillvalue=None):
    "Collect data into fixed-length chunks or blocks"
    # grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx
    args = [iter(iterable)] * n
    return izip_longest(fillvalue=fillvalue, *args)

答案 2 :(得分:0)

您可以使用struct模块读取和写入二进制数据。 (链接到文档here。)

修改

对不起,我被你的头衔误导了。我只是明白你在文本文件中写二进制数据而不是直接写二进制数据。

答案 3 :(得分:0)

好的,感谢alexis,并且知道Ignacio关于填充的警告,我找到了一种方法来做我想做的事情,即将数据读入二进制表示并将二进制表示写入文件:

def padd(bitstring):
    padding = ''
    for i in range(8-len(bitstring)):
        padding += '0'
    bitstring = padding + bitstring
    return bitstring

file = open('INPUT','rb')
data = file.read()
data_2 = "".join( padd(bin(ord(c))[2:]) for c in data )

OUT = open('OUTPUT','wb')

i = 0
while i < len(data_2) / 8:
    byte = int(data_2[i*8 : (i+1)*8], 2)
    OUT.write('%c' % byte)
    i += 1

OUT.close()

如果我没有完全按照亚历克西斯提出的那样做,那是因为它不起作用。当然这非常慢,但现在我可以做最简单的事情,我可以进一步优化它。