Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/286.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
python二进制字符串到二进制数据_Python - Fatal编程技术网

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

python二进制字符串到二进制数据,python,Python,我的哈夫曼编码项目有问题 我有一个文件的二进制表示字符串,但从逻辑上讲,当我将其保存为文本文件时,它比原始文件更大。我想要的是将文件保存为二进制文件 示例:在哈夫曼编码之后,让a b c和d由以下“二进制代码”表示 因此,一个文件的文本abcd由binary=表示为“00100110101” 如果我将连接的二进制表示字符串保存为普通文本文件,它将比原始的abcd大 但我需要将二进制连接文件保存为实际的二进制文件,该文件的大小会降低-例如,最初的示例是abcd=8bit*4=32位,但之后,我需要

我的哈夫曼编码项目有问题

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

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

因此,一个文件的文本
abcd
由binary=
表示为“00100110101”

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

但我需要将二进制连接文件保存为实际的二进制文件,该文件的大小会降低-例如,最初的示例是
abcd=8bit*4=32位
,但之后,我需要它为13位

我正在用python做这件事

import struct
with open("foo.bin", 'wb') as f:
    f.write(struct.pack('h', 0b0010010110101))
将2个字节(16位)作为短整数(
h
)。您可以使用定义自己的格式字符串,但我不确定您是否能够使用字节大小

编辑

根据你的评论,这里有一点背景:

在文件中写入内容时,总是将其转换为二进制文件。字符是使用某种称为编码(如ASCII)的规则进行编码的,其中每个字符都映射到一个数字,该数字本身用二进制表示。这样,数字00100100(36)和字符“$”是相同的在文件上由36表示,您之间的软件层(如编辑器)将把遇到的每个“00100100”渲染为字符“$”

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

用于编写文件的Python API总是在编写字符串,即它将自动执行此转换字符串->二进制数,我不知道有什么方法可以覆盖它。但是,您可以生成字符串,使其二进制表示形式成为您想要写入的实际二进制字符串:如果您想要在文件中写入数字00100100,您只需写入
f.write(“$”)
,这实际上是一样的

这正是“struct”模块执行的功能:它生成一个字节或字符字符串,这些字节或字符与您提供的数字完全匹配

在我的示例中,我给它编号
0B0010110101
,并告诉它将其编码为
short
整数,即两个字节。如果在Python解释器中执行
struct.pack('h',1205)
,它将打印出两个字符(字节)
\xb5\x04
,这两个字符对应于“字节基”中的这个数字,即基256(采用大端惯例)。事实上:

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

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))
这是一种非常粗糙且不是超高效的处理方式,但它确实会将每个字节转换为相应的字符,并返回相应的字符串,您可以直接将其写入文件:

>>> encode('001001001010100100100100100111110010101110100')
'\x04\x95$\x93\xe5t'
事实上,将其写入文件会产生6个字节,对应于6个字符:

with open("foo.bin", 'wb') as f:
    f.write('\x04\x95$\x93\xe5t')

>>> os.path.getsize("foo.bin")
6L
struct
模块执行完全相同的操作,除了使用固定格式,并且以更高效的方式执行。而不是获取与整数对应的
chr

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
中的字符相同。唯一不同的是顺序,具体取决于转换的结束度)

然后还可以使用
struct
和相同格式的字符串对这些字符进行解码:

>>> 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文件API只能处理字符,这些字符实际上是字节。也许有一些神奇的方法可以将单个位写入文件,但我不太相信这一点,因为这会带来很多问题,字节在99%的情况下已经足够了。要写入二进制数据,请以256为基数表示,并将其每个b256数字转换为相应的字符。根据定义,此字符串的二进制表示是您的原始数字。

binascii

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_字符串
应该是偶数,因此您需要在
“001001011001”
中添加一位,以使
不精确
正常工作。

我正在写入字符串,这是我的问题,我想将其作为位写入!通过将位模式“0110001”(“a”)替换为“0010”,可以压缩文本。你难道没有忘记,每一组8位都整齐地组合成一个字节吗?问题是什么???@Jongware那么你认为我应该怎么做!我的意思是,这就是哈夫曼编码的结果,它用更少的比特表示一个更重复的字符,所以让我把我的问题转到哈夫曼压缩,我怎么能做到这一点!获取每个字符的映射后的步骤代码@simonmorley在哈夫曼压缩后得到每个字符地图的步骤代码!
>>> 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'
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))