Зачем мне нужно '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 "<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
Почему это?
Ответы
Ответ 1
base64-кодирование принимает 8-битные двоичные байтовые данные и кодирует его, используя только символы A-Z
, A-Z
, 0-9
, +
, /
*, поэтому он может передаваться по каналам, которые не сохраняются все 8-битные данные, такие как электронная почта.
Следовательно, он хочет строку из 8-битных байтов. Вы создаете их в Python 3 с синтаксисом b''
.
Если вы удалите b
, он станет строкой. Строка представляет собой последовательность символов Юникода. 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 могут использовать символы, отличные от +
и /
. Подробнее см. В сводной таблице вариантов в Википедии.
Ответ 2
Короткий ответ
Вам нужно нажать 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 в Python 3
Первоначально заголовок вопроса спрашивал о кодировке Base-64. Читайте дальше для материала Base-64.
base64
кодирование принимает 6-битные двоичные фрагменты и кодирует их с использованием символов AZ, az, 0-9, '+', '/' и '=' (некоторые кодировки используют вместо символов "+" и "/" разные символы,). Это кодировка символов, основанная на математической конструкции системы чисел radix-64 или base-64, но они очень разные. Base-64 в математике - это система чисел, такая как двоичная или десятичная, и вы делаете это изменение радиуса на весь номер, или (если радиус, из которого вы конвертируете, имеет мощность 2 меньше 64) в кусках справа оставил.
В кодировке base64
перевод выполняется слева направо; эти первые 64 символа являются причиной того, что он называется кодировкой base64
. Символ 65-го '=' используется для заполнения, поскольку кодирование вытягивает 6-битные куски, но данные, которые обычно предназначены для кодирования, являются 8-битными байтами, поэтому иногда в последнем фрагменте всего два или четыре бита.
Пример:
>>> 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 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 '
>>>
Есть две проблемы, которые я поставил:
- Если бы я попытался отправить это письмо в Unix, письмо отправит, как только будет
\x04
символ \x04
, потому что это ASCII для END-OF-TRANSMISSION
(Ctrl-D), так что оставшиеся данные будут исключены из коробка передач. - Кроме того, хотя Python достаточно умен, чтобы избежать всех моих злых контрольных символов, когда я печатаю данные напрямую, когда эта строка декодируется как ASCII, вы можете видеть, что "msg" не существует. Это потому, что я использовал три символа
BACKSPACE
и три SPACE
чтобы стереть "msg". Таким образом, даже если бы у меня не было символа EOF
конечный пользователь не смог бы перевести текст с экрана на реальные необработанные данные.
Это просто демоверсия, чтобы показать вам, как сложно просто отправить необработанные данные. Кодирование данных в формат base64 дает вам точные данные, но в формате, который гарантирует, что он безопасен для отправки через электронные носители, такие как электронная почта.
Ответ 3
Если кодируемые данные содержат "экзотические" символы, я думаю, вам нужно кодировать в "UTF-8"
encoded = base64.b64encode (bytes('data to be encoded', "utf-8"))
Ответ 4
Есть все, что вам нужно:
expected bytes, not str
Ведущий b
делает ваш двоичный файл.
Какую версию Python вы используете? 2.x или 3.x?
Изменить: Смотрите http://docs.python.org/release/3.0.1/whatsnew/3.0.html#text-vs-data-instead-of-unicode-vs-8-bit для подробных сведений о строках в Python 3.x
Ответ 5
Если строка является Unicode, самый простой способ:
import base64
a = base64.b64encode(bytes(u'complex string: ñáéíóúÑ', "utf-8"))
# a: b'Y29tcGxleCBzdHJpbmc6IMOxw6HDqcOtw7PDusOR'
b = base64.b64decode(a).decode("utf-8", "ignore")
print(b)
# b :complex string: ñáéíóúÑ
Ответ 6
Это просто означает, что вы воспринимаете ввод как байты или байты, а не как строки.