为什么我需要使用“b”来使用Base64编码字符串?

24 浏览
0 Comments

为什么我需要使用“b”来使用Base64编码字符串?

按照这篇Python示例,我用以下代码将字符串编码为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 "", line 1, in 
  File "C:\Python32\lib\base64.py", line 56, in b64encode
   raise TypeError("expected bytes, not %s" % s.__class__.__name__)
   TypeError: expected bytes, not str

为什么会这样呢?

admin 更改状态以发布 2023年5月21日
0
0 Comments

简短回答

您需要将bytes-like对象(bytes, bytearray,等等)推送到 base64.b64encode() 方法中。以下是两种方式:

>>> import base64
>>> data = base64.b64encode(b'data to be encoded')
>>> print(data)
b'ZGF0YSB0byBiZSBlbmNvZGVk'

或者使用变量:

>>> import base64
>>> string = 'data to be encoded'
>>> data = base64.b64encode(string.encode())
>>> print(data)
b'ZGF0YSB0byBiZSBlbmNvZGVk'

为什么?

在Python 3中,str对象不是C风格的字符数组(因此它们不是字节数组),而是没有任何固有编码的数据结构。您可以以各种方式对该字符串进行编码(或解释)。最常见的是utf-8(在Python 3中是默认值),特别是因为它与ASCII向后兼容(虽然大多数使用广泛的编码方式都是)。当您拿到一个string并对其调用.encode()方法时,这就是发生了什么:Python正在解释该字符串的utf-8(默认编码),并为您提供它对应的字节数组。

Python 3中的Base-64编码

最初,问题标题问的是Base-64编码。继续阅读有关Base-64的内容。

base64编码使用A-Z,a-z,0-9,'+','/'和'='(某些编码在'+'和'/'的位置使用不同的字符)来对6位二进制块进行编码。这是基于基数64或Base-64数字系统的数学构造的字符编码,但它们非常不同。Base-64在数学上是像二进制或十进制之类的数字系统,您可以对整个数字或(如果您从的基数是小于64的2的幂)从右到左在块中执行该基数更改。

base64 编码中,转换是从左往右进行的;前 64 个字符是为什么它称为 base64 编码 的原因。第 65 个 '=' 符号用于填充,因为编码会提取 6 位的块,但通常要编码的数据是 8 位的字节,因此最后一个块中可能只有两个或 4 个位。

例如:

>>> data = b'test'
>>> for byte in data:
...     print(format(byte, '08b'), end=" ")
...
01110100 01100101 01110011 01110100
>>>

如果你将二进制数据解释为一个整数,那么这就是将其转换为十进制和 base64base-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   '
>>>

我设置了两个问题:

  1. 如果我尝试在Unix中发送那封电子邮件,那么在读取到\x04字符时,邮件就会立即发送,因为这是ASCII码的END-OF-TRANSMISSION(Ctrl-D),因此剩余的数据将被省略。
  2. 此外,虽然Python足够聪明,可以在直接打印数据时转义所有恶意的控制字符,但当该字符串解码为ASCII码时,可以看到该“msg”不存在。这是因为我使用了三个BACKSPACE字符和三个SPACE字符来清除“msg”。因此,即使在没有EOF字符的情况下,最终用户也无法将屏幕上的文本转换为真正的原始数据。

这只是一个演示,展示了简单发送原始数据是多么困难。将数据编码为base64格式可以获得完全相同的数据,但以确保对于电子媒体(如电子邮件)的发送是安全的格式。

0
0 Comments

base64编码将8位二进制字节数据编码为只使用字符A-Za-z0-9+/的字符串,因此可以在不保留所有8位数据的通道上传输,例如电子邮件。

因此,它需要一串8位字节。在Python 3中,您可以使用b''语法创建这些字节。

如果您删除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变种可能使用除+/之外的字符。请参见维基百科上的变种汇总表,以获得概述。

0