在python example之后,我将字符串编码为Base64,其中包含:
>>> import base64
>>> encoded = base64.b64encode(b'data to be encoded')
>>> encoded
b'ZGF0YSB0byBiZSBlbmNvZGVk'
但是,如果我遗漏了领先的b
:
>>> encoded = base64.b64encode('data to be encoded')
我收到以下错误:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\Python32\lib\base64.py", line 56, in b64encode
raise TypeError("expected bytes, not %s" % s.__class__.__name__)
TypeError: expected bytes, not str
为什么会这样?
答案 0 :(得分:210)
base64编码采用8位二进制字节数据并对其进行编码仅使用字符A-Z
,a-z
,0-9
,+
,/
*所以它可以通过不保留所有8位数据的通道传输,例如电子邮件。
因此,它需要一个8位字节的字符串。您可以使用b''
语法在Python 3中创建它们。
如果删除b
,它将变为字符串。字符串是一系列Unicode字符。 base64不知道如何处理Unicode数据,它不是8位。事实上,这并不是真的。 : - )
在你的第二个例子中:
>>> encoded = base64.b64encode('data to be encoded')
所有字符都整齐地适合ASCII字符集,因此base64编码实际上有点无意义。您可以使用
将其转换为ascii>>> encoded = 'data to be encoded'.encode('ascii')
或更简单:
>>> encoded = b'data to be encoded'
在这种情况下,这将是同一件事。
*大多数base64风格最后还可能包含=
作为填充。此外,某些base64变体可能使用+
和/
以外的字符。有关概述,请参阅维基百科的Variants summary table。
答案 1 :(得分:131)
您需要将bytes-like
对象(bytes
,bytearray
等)推送到base64.b64encode()
方法。这有两种方式:
>>> data = base64.b64encode(b'data to be encoded')
>>> print(data)
b'ZGF0YSB0byBiZSBlbmNvZGVk'
或使用变量:
>>> string = 'data to be encoded'
>>> data = base64.b64encode(string.encode())
>>> print(data)
b'ZGF0YSB0byBiZSBlbmNvZGVk'
在Python 3中,str
对象不是C风格的字符数组(因此它们是不是字节数组),而是它们是没有任何固有编码的数据结构。您可以通过各种方式对该字符串进行编码(或解释它)。最常见的(在Python 3中是默认的)是utf-8,特别是因为它向后兼容ASCII(尽管是最广泛使用的编码)。这就是当您使用string
并在其上调用.encode()
方法时发生的事情:Python正在解释utf-8中的字符串(默认编码)并为您提供它对应的字节数组到。
最初问题标题是关于Base-64编码的。继续阅读Base-64的内容。
base64
编码采用6位二进制块并使用字符AZ,az,0-9,'+','/'和'='对它们进行编码(某些编码使用不同的字符代替'+'和'/')。这是一个基于radix-64或base-64数字系统的数学结构的字符编码,但它们是非常不同的。数学中的Base-64是一个数字系统,如二进制或十进制,你可以在整个数字上进行基数更改,或者(如果你转换的基数是2的幂小于64)从右到右的块左
在base64
编码中,翻译是从左到右完成的;前64个字符是base64
编码的原因。第65个'='符号用于填充,因为编码会拉出6位块,但通常要编码的数据是8位字节,所以有时在最后一个块中只有两个或4个位。
示例:
>>> data = b'test'
>>> for byte in data:
... print(format(byte, '08b'), end=" ")
...
01110100 01100101 01110011 01110100
>>>
如果您将该二进制数据解释为单个整数,那么您可以将其转换为base-10和base-64(table for base-64):
base-2: 01 110100 011001 010111 001101 110100 (base-64 grouping shown)
base-10: 1952805748
base-64: B 0 Z X N 0
然而, base64
编码会重新对这些数据进行分组:
base-2: 011101 000110 010101 110011 011101 00(0000) <- pad w/zeros to make a clean 6-bit chunk
base-10: 29 6 21 51 29 0
base-64: d G V z d A
因此,'B0ZXN0'是我们二进制的base-64版本,从数学上讲。但是,base64
编码必须以相反的方向进行编码(因此原始数据会转换为'dGVzdA')并且还有一条规则告诉其他应用程序剩余多少空间在最后。这是通过用'='符号填充末尾来完成的。因此,此数据的base64
编码为'dGVzdA ==',其中两个'='符号表示当此数据被解码以使其与原始数据匹配时,需要从末尾删除两对位数据
让我们测试一下,看看我是不是在做不诚实:
>>> encoded = base64.b64encode(data)
>>> print(encoded)
b'dGVzdA=='
base64
编码?假设我必须通过电子邮件向某人发送一些数据,例如:
>>> data = b'\x04\x6d\x73\x67\x08\x08\x08\x20\x20\x20'
>>> print(data.decode())
>>> print(data)
b'\x04msg\x08\x08\x08 '
>>>
我种植了两个问题:
\x04
字符后立即发送电子邮件,因为这是END-OF-TRANSMISSION
的ASCII(Ctrl-D),因此其余数据将被排除在传输之外。BACKSPACE
字符和三个SPACE
字符来删除'msg'。因此,即使我没有EOF
字符,最终用户也无法从屏幕上的文本转换为真实的原始数据。这只是一个演示,向您展示简单地发送原始数据是多么困难。将数据编码为base64格式可以为您提供完全相同的数据,但格式可确保通过电子邮件等电子媒体进行发送是安全的。
答案 2 :(得分:29)
如果要编码的数据包含“异国情调”字符,我认为你必须编码为“UTF-8”
encoded = base64.b64encode (bytes('data to be encoded', "utf-8"))
答案 3 :(得分:12)
您需要的一切:
expected bytes, not str
前导b
会使您的字符串成为二进制文件。
您使用的是哪个版本的Python? 2.x或3.x?
修改:有关Python 3.x中字符串的详细信息,请参阅http://docs.python.org/release/3.0.1/whatsnew/3.0.html#text-vs-data-instead-of-unicode-vs-8-bit
答案 4 :(得分:12)
如果字符串是unicode,最简单的方法是:
import base64
a = base64.b64encode(bytes(u'complex string: ñáéíóúÑ', "utf-8"))
b = base64.b64decode(a).decode("utf-8", "ignore")
print(b)
答案 5 :(得分:0)
b只是意味着您将输入作为字节或字节数组而不是字符串。