首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >python二进制字符串到二进制数据

python二进制字符串到二进制数据
EN

Stack Overflow用户
提问于 2014-01-03 12:26:36
回答 2查看 2.4K关注 0票数 0

我对我的赫夫曼编码项目有个问题。

我有一个文件的二进制表示的字符串,但从逻辑上讲,当我将原始文件保存为文本文件时,它甚至更大。我想要的是将文件保存为二进制文件。

示例:在Huffman编码之后,让a、b、c和d由以下“二进制代码”表示

代码语言:javascript
复制
a="0010" b="010" c="110" d="101"

因此,一个以二进制= "0010010110101"表示的文本"0010010110101"的文件

如果我将连接的二进制表示字符串保存为普通文本文件,则它比原始的abcd要大。

但是我需要将二进制连接文件保存为真正的二进制文件,它的大小已经降低--例如,最初的abcd= 8bit*4 = 32 bits,但之后,我需要它是13位。

我正在用蟒蛇做这个。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2014-01-03 12:42:16

代码语言:javascript
复制
import struct
with open("foo.bin", 'wb') as f:
    f.write(struct.pack('h', 0b0010010110101))

将两个字节(16位)作为一个短整数(h)。您可以使用结构模块定义您自己的格式字符串,但我不确定您是否能够低于字节大小。

编辑

根据您的评论,这里有一些上下文:

在文件中写入某些内容时,总是将其转换为二进制文件。字符使用某种规则进行编码,称为编码(例如ASCII),其中每个字符被映射到一个数字,其本身以二进制表示。这样,数字00100100 (36)和字符'$‘是相同的东西。“$”由文件上的36表示,您之间的软件层(例如编辑器)会将它遇到的每一个'00100100‘呈现为字符'$’。

现在,当您将字符串“00100100”写入文件时,它将打印字符“0”、“1”等.因此,字符串 '00100100‘由二进制数表示。这是必要的,因为输入是一个字符串,您需要一种明确的方式来表示所有可能的8个字符长的字符串,而不仅仅是表示0和1的字符串。

用于编写文件的Python总是在写入字符串,也就是说,它将自动执行这个转换字符串->二进制数字,我不知道有什么方法可以重写它。但是,您可以做的是生成字符串,以便它的二进制表示形式是您想要写入的实际二进制字符串:如果您想要在文件中写入数字00100100,可以只编写f.write('$'),这实际上是一回事。

这正是'struct‘模块所执行的:它生成一个字节或字符字符串,与您提供的数字完全匹配。

在我的示例中,我给它一个数字0b0010010110101,并告诉它将它编码为一个short整数,即两个字节。如果在Python解释器中执行struct.pack('h', 1205),它将在‘字节基’中打印出与这个数字对应的两个字符(字节) \xb5\x04,即基256 (具有大端惯例)。的确:

代码语言:javascript
复制
>>> 0x04 * 256 + 0xb5
1205

就像您可以表示基础10 (例如36)、基数16 (例如0x24)、基数2(例如0b100100)中的任何十进制数一样,您也可以通过ASCII编码(例如'$')将其表示为基256。Struct正是这样做的,还为您正在编写的数据类型提供了一个方便的“fmt”字符串约定。还可以通过将每个字节转换为相应的字符来直接完成此任务:

代码语言:javascript
复制
def encode(binary):
    # Aligning on bytes
    binary = '0' * (8 - len(binary) % 8) + binary
    # Generating the corresponding character for each
    # byte encountered
    return ''.join(chr(int('0b' + binary[i:i+8], base = 2)) 
                   for i in xrange(0, len(binary), 8))

这是一种非常粗糙且不太有效的处理方法,但它确实将每个字节转换为相应的字符,并返回相应的字符串,您可以直接将该字符串写入文件中:

代码语言:javascript
复制
>>> encode('001001001010100100100100100111110010101110100')
'\x04\x95$\x93\xe5t'

实际上,将其写入文件会产生6个字节,对应于以下6个字符:

代码语言:javascript
复制
with open("foo.bin", 'wb') as f:
    f.write('\x04\x95$\x93\xe5t')

>>> os.path.getsize("foo.bin")
6L

struct模块执行完全相同的事情,除了以固定的格式执行,并且以更高效的方式执行。而不是获取与整数对应的chr

代码语言:javascript
复制
def encode2(binary):
    rawbytes = []
    while binary > 0:
        binary, byte = divmod(binary, 256)
        rawbytes.append(byte)
    fmt_string = '%sB' % len(rawbytes)
    print "Encoding %s into %s bytes (%s)" % (rawbytes, len(rawbytes), fmt_string)
    return struct.pack(fmt_string, *rawbytes)

>>> encode2(0b001001001010100100100100100111110010101110100)
Encoding [116L, 229L, 147L, 36L, 149L, 4L] into 6 bytes (6B)
't\xe5\x93$\x95\x04'

(注意,这些字符与encode中输出的字符相同。唯一的区别是顺序,取决于转换的endianness )。

然后,您也可以使用struct和相同的格式字符串解码这些字符:

代码语言:javascript
复制
>>> bytes = struct.unpack('6B', 't\xe5\x93$\x95\x04')
>>> bytes
(116, 229, 147, 36, 149, 4)
>>> bin(sum(x * 256 ** i for i, x in enumerate(bytes)))
'0b1001001010100100100100100111110010101110100'

这是我们的原始号码。

底线是: Python只能处理字符,这实际上是字节。可能有一些神奇的方法可以将单个位写入文件,但我不太相信这一点,因为这引入了它自己的问题世界,在99%的情况下,字节已经足够了。若要写入二进制数据,请将其表示为基256,并将其每个b256数字转换为相应的字符。根据定义,此字符串的二进制表示形式是您的原始数字。

票数 2
EN

Stack Overflow用户

发布于 2014-01-03 12:58:57

可以使用binascii

代码语言:javascript
复制
import binascii

a = "1010"
b = "10"
c = "00"

data = a + b + c
hex_string = hex(int(data, 2))[2:]  #remove '0x'

with open('foo', 'wb') as f:
    f.write(binascii.unhexlify(hex_string))

hex_string应该是均匀的,所以您需要向"0010010110101"添加一点以使unhexlify正常工作。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/20903643

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档