为什么我需要'b'用Base64编码Pythonstring?
在这个python示例之后 ,我使用下面的代码将一个string编码为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
为什么是这样?
base64编码采用8位二进制字节数据,并对其进行编码,仅使用AZ
, az
, 0-9
, +
, /
*字符,因此可以通过不保留所有8位数据的通道(如电子邮件)进行传输。
因此,它需要一个8位字节的string。 你用Python b''
语法创build了Python 3。
如果你删除了b
,它就变成了一个string。 一个string是一个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风格也可能包括a =
在最后作为填充。 另外,一些base64变体可能会使用+
和/
以外的字符。 查看维基百科的变体汇总表以获得总览。
简答
您需要将类似bytes-like
对象( bytes
, bytearray
等) base64.b64encode()
方法。 这里有两种方法:
>>> data = base64.b64encode(b'data to be encoded') >>> print(data) b'ZGF0YSB0byBiZSBlbmNvZGVk'
或者用一个variables:
>>> string = 'data to be encoded' >>> data = base64.b64encode(string.encode()) >>> print(data) b'ZGF0YSB0byBiZSBlbmNvZGVk'
更长的答案:在Python 3 Base-64编码
base64
编码采用6位二进制块,并使用字符AZ,az,0-9,“+”,“/”和“=”(某些编码使用不同的字符代替“+”和“/” )。 这是一个字符编码,它是基于基数-64或基数-64数字系统的math结构,但它们是非常不同的。 math中的Base-64是一个二进制或十进制的数字系统,你可以在整个数字上做这个基数的变化,或者(如果你正在转换的基数是2的幂小于64)剩下。
在base64
编码中,翻译是从左到右完成的; 那些前64个字符是为什么它被称为base64
编码 。 第65个'='符号用于填充,因为编码拉取了6位块,但是通常要编码的数据是8位字节,所以有时最后一个块中只有2或4位。
例:
>>> data = b'test' >>> for byte in data: ... print(format(byte, '08b'), end=" ") ... 01110100 01100101 01110011 01110100 >>>
如果你将这个二进制数据解释为一个整数,那么这就是你将它转换为base-10和base-64(base-64的表 )的方式:
base-2: 01 110100 011001 010111 001101 110100 (base-64 grouping shown) base-10: 1952805748 base-64: B 0 ZXN 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 GV zd A
所以,'B0ZXN0'是我们的二进制的基础版本,在math上讲。 但是, base64
编码必须在相反的方向上进行编码(所以原始数据被转换为“dGVzdA”),并且还有一个规则来告诉其他应用程序末尾剩余多less空间。 这是通过用'='符号填充结尾来完成的。 所以,这个数据的base64
编码是'dGVzdA ==',当这个数据被解码以使它与原始数据相匹配时,用两个'='符号来表示两对比特将需要从结尾去除。
我们来testing一下,看看我是不是不诚实:
>>> encoded = base64.b64encode(data) >>> print(encoded) b'dGVzdA=='
现在到你的问题的关键:在Python 3中, str
对象不是C风格的字符数组(所以它们不是字节数组),而是没有任何固有的或假定的编码的数据结构。 您可以用多种方式编码该string(或解释它)。 最常见的(在Python 3中是默认的)是UTF-8,特别是因为它与ASCII向后兼容(尽pipe和最广泛使用的编码一样)。 这就是当你拿一个string
并调用.encode()
方法时发生的事情:Python正在用.encode()
-8(默认编码)解释string。
为什么使用base64
编码?
比方说,我必须通过电子邮件将某些数据发送给某人,例如:
>>> data = b'\x04\x6d\x73\x67\x08\x08\x08\x20\x20\x20' >>> print(data.decode()) >>> print(data) b'\x04msg\x08\x08\x08 ' >>>
我种了两个问题:
- 如果我试图在Unix中发送这封电子邮件,
\x04
读取了\x04
字符,电子邮件就会发送,因为这是用于END-OF-TRANSMISSION
(Ctrl-D)的ASCII码,所以剩下的数据将不在传输。 - 另外,当我直接打印数据的时候,Python足够聪明地转义所有的邪恶控制字符,当这个string被解码为ASCII时,你可以看到'msg'不存在。 那是因为我使用了三个
BACKSPACE
字符和三个SPACE
字符来擦除“味精”。 因此,即使我没有EOF
字符,最终用户也不能从屏幕上的文本转换为真实的原始数据。
这只是一个演示,告诉你如何简单地发送原始数据。 将数据编码为base64格式将为您提供完全相同的数据,但格式可确保通过电子邮件等电子媒体进行发送。
如果要编码的数据包含“异国情调”的字符,我认为你必须编码为“UTF-8”
encoded = base64.b64encode (bytes('data to be encoded', "utf-8"))
有你需要的一切:
expected bytes, not str
前导b
使你的string变成二进制。
你使用什么版本的Python? 2.x还是3.x?
如果string是unicode,最简单的方法是:
import base64 a = base64.b64encode(bytes(u'complex string: ñáéíóúÑ', "utf-8")) b = base64.b64decode(a).decode("utf-8", "ignore") print(b)