Base64로 문자열을 인코딩하려면 왜 'b'가 필요합니까?


258

파이썬 예제에 따라 문자열을 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

왜 이런거야?


37
실제로 "TypeError : 예상 바이트, str이 아님"을 반환하는 모든 질문에는 같은 대답이 있습니다.
Lennart Regebro

답변:


273

베이스 64 인코딩이 사용하는 8 비트 이진 바이트 데이터 인코딩 소요 자만 A-Z, a-z, 0-9, +, /*가 이메일과 같은 모든 데이터를 8 비트를 보존하지 않는 채널을 통해 전송 될 수 있도록.

따라서 8 비트 바이트의 문자열을 원합니다. b''구문을 사용하여 Python 3에서 생성 합니다.

를 제거하면 b문자열이됩니다. 문자열은 일련의 유니 코드 문자입니다. base64는 유니 코드 데이터로 무엇을해야할지 전혀 몰라 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 변형은 +및 이외의 문자를 사용할 수 있습니다 /. 개요는 Wikipedia 의 변형 요약 표 를 참조하십시오 .


174

짧은 답변

당신은 추진해야 할 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 스타일의 문자 배열이 아니므로 바이트 배열이 아니라 고유 한 인코딩이없는 데이터 구조입니다. 해당 문자열을 다양한 방식으로 인코딩하거나 해석 할 수 있습니다. 가장 일반적으로 사용되는 파이썬 3의 기본값은 utf-8이며, 특히 ASCII와 호환됩니다 (가장 널리 사용되는 인코딩 임에도 불구하고). 즉 당신이 걸릴 때 무슨 일이 일어나고있는 것입니다 string과 전화 .encode()파이썬은 UTF-8 문자열 (기본 인코딩)을 해석하고 당신이에 해당 바이트의 배열을 제공 : 거기에 방법을.

Python 3의 Base-64 인코딩

원래 제목은 Base-64 인코딩에 관한 질문이었습니다. Base-64에 대해 읽어보십시오.

base64인코딩은 6 비트 이진 청크를 사용하고 AZ, az, 0-9, '+', '/'및 '='문자를 사용하여 인코딩합니다 (일부 인코딩은 '+'및 '/'대신 다른 문자를 사용함) . 이것은 radix-64 또는 base-64 숫자 시스템의 수학적 구성을 기반으로하는 문자 인코딩이지만 매우 다릅니다. 수학의 Base-64는 이진수 또는 십진수와 같은 숫자 시스템이며 정수에서 또는 (변환하는 기수가 64보다 작은 2의 거듭 제곱 인 경우) 오른쪽에서 왼쪽.

에서 base64인코딩, 번역은 왼쪽에서 오른쪽으로 이루어집니다; 첫 64자인 이유는 base64 인코딩 이라고 합니다. 인코딩은 6 비트 청크를 가져 오지만 일반적으로 인코딩하려는 데이터는 8 비트 바이트이므로 마지막 청크에는 2 또는 4 비트 만 있기 때문에 65 번째 '='기호는 패딩에 사용됩니다.

예:

>>> 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 그러나 encoding 은이 데이터를 다음과 같이 다시 그룹화합니다.

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문자가 읽히자 마자 이메일이 전송됩니다. 문자는 END-OF-TRANSMISSION(Ctrl-D)의 ASCII 이므로 나머지 데이터는 전송에서 제외됩니다.
  2. 또한 파이썬은 데이터를 직접 인쇄 할 때 모든 사악한 제어 문자를 피할 수있을만큼 똑똑하지만 해당 문자열이 ASCII로 디코딩되면 'msg'가 없다는 것을 알 수 있습니다. 3 개의 BACKSPACE문자와 3 개의 SPACE문자를 사용하여 'msg'를 지우기 때문입니다. 따라서 EOF문자가 없더라도 최종 사용자는 화면의 텍스트를 실제 원시 데이터로 번역 할 수 없습니다.

이것은 단순히 원시 데이터를 보내는 것이 얼마나 어려운지를 보여주는 데모 일뿐입니다. 데이터를 base64 형식으로 인코딩하면 정확히 동일한 데이터가 제공되지만 전자 메일과 같은 전자 매체를 통해 안전하게 전송할 수있는 형식으로 제공됩니다.


6
base64.b64encode(s.encode()).decode()원하는 것이 문자열에서 문자열로 변환 될 때 매우 파이썬 적이 지 않습니다. base64.encode(s)적어도 python3에서는 충분해야합니다. 파이썬에서 문자열과 바이트에 대해 아주 잘 설명해 주셔서 감사합니다
MortenB

2
@ MortenB 그래, 이상하지만, 다른 언어와 같이 단일 배열 (인코딩)이 없기 때문에 엔지니어가 바이트 배열과 문자열의 차이점을 알고있는 한 무슨 일이 일어나고 있는지 분명합니다. 취하다.
Greg Schmit

3
@MortenB 그건 그렇고, base64.encode(s)Python3에서는 작동하지 않습니다. 그런 것을 사용할 수 있어야한다고 말하는가? 혼란 스러울 수있는 이유는 인코딩과 문자열 내용에 따라 s바이트 배열로 1 개의 고유 한 표현을 가질 수 없기 때문입니다.
Greg Schmit

슈미트 : 그것은 얼마나 간단한 지에 대한 예일뿐입니다. 가장 일반적인 사용 사례는 이와 같아야합니다.
MortenB

1
@MortenB이지만 b64는 텍스트만을위한 것이 아니며 모든 바이너리 컨텐츠는 b64로 인코딩 될 수 있습니다 (오디오, 이미지 등). 내 의견으로는 제안대로 작동하게하면 텍스트와 바이트 배열의 차이점이 훨씬 더 숨겨져 디버깅이 더 어려워집니다. 어려움을 다른 곳으로 옮깁니다.
Michael Ekoka

32

인코딩 할 데이터에 "이국적인"문자가 포함되어 있으면 "UTF-8"로 인코딩해야한다고 생각합니다

encoded = base64.b64encode (bytes('data to be encoded', "utf-8"))

24

문자열이 유니 코드 인 경우 가장 쉬운 방법은 다음과 같습니다.

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: ñáéíóúÑ

실제로 가장 쉬운 방법은 아니지만 base64를 통한 데이터 전송의 "프로토콜"의 일부인 문자열을 전송하는 데 사용되는 인코딩이 중요한 경우 가장 명확한 방법 중 하나입니다.
xuiqzy

12

필요한 모든 것이 있습니다 :

expected bytes, not str

행간 b은 문자열을 이진으로 만듭니다.

어떤 버전의 Python을 사용하십니까? 2.x 또는 3.x?

편집 : Python에서 문자열에 대한 자세한 내용은 http://docs.python.org/release/3.0.1/whatsnew/3.0.html#text-vs-data-instead-of-unicode-vs-8-bit 를 참조 하십시오 3.x


감사합니다. 3.x를 사용하고 있습니다. 파이썬이 왜 그것을 명시 적으로 바이너리로 변환하려고합니까? 루비에서도 마찬가지입니다 ...> "base64"그리고> Base64.encode64 ( '인코딩 될 데이터')
dublintech

2
@dublintech (유니 코드) 텍스트는 원시 데이터와 다르기 때문입니다. Base64에서 텍스트 문자열을 인코딩하려면 먼저 문자 인코딩 (UTF-8과 같은)을 결정한 다음 문자가 아닌 바이트를 사용하여 텍스트를 안전한 ASCII 형식으로 인코딩 할 수 있습니다.
포트란

2
이것은 질문에 대답하지 않습니다. 그는 그것이 바이트 객체에서는 작동하지만 문자열 객체에서는 작동하지 않는다는 것을 알고 있습니다. 문제는 이유 입니다.
Lennart Regebro

@fortran 기본 Python3 문자열 인코딩은 UTF입니다. 몰라 왜 명시 적으로 설정해야합니까?
xmedeko

0

b는 단순히 문자열이 아닌 바이트 또는 바이트 배열로 입력을 받고 있음을 의미합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.