Warum brauche ich ‘b’, um eine Zeichenfolge mit Base64 zu codieren?

Lesezeit: 9 Minuten

Benutzer-Avatar
Dublintech

Im Anschluss daran Python-Beispielkodiere ich eine Zeichenfolge als Base64 mit:

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

Aber wenn ich den Anfang weglasse b:

>>> encoded = base64.b64encode('data to be encoded')

Ich bekomme folgenden Fehler:

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

Warum ist das?

  • Tatsächlich haben alle Fragen, die “TypeError: erwartete Bytes, nicht str” zurückgeben, dieselbe Antwort.

    – Lennart Regebro

    18. Januar 2012 um 13:33 Uhr

  • Das b bedeutet einfach, dass Sie die Eingabe als Bytes oder Bytes-Array und nicht als Zeichenfolge nehmen.

    – Atul6.Singh

    20. Januar 2019 um 19:13 Uhr

Benutzer-Avatar
Lennart Regebro

Die base64-Codierung nimmt 8-Bit-Binärbyte-Daten und codiert nur die Zeichen A-Z, a-z, 0-9, +, /* damit es über Kanäle übertragen werden kann, die nicht alle 8-Bit-Daten bewahren, wie z. B. E-Mail.

Daher möchte es eine Zeichenfolge von 8-Bit-Bytes. Diese erstellen Sie in Python 3 mit dem b'' Syntax.

Wenn Sie die entfernen b, es wird eine Zeichenfolge. Ein String ist eine Folge von Unicode-Zeichen. base64 hat keine Ahnung, was mit Unicode-Daten zu tun ist, es ist nicht 8-Bit. Es sind nicht wirklich irgendwelche Bits, in der Tat. 🙂

In deinem zweiten Beispiel:

>>> encoded = base64.b64encode('data to be encoded')

Alle Zeichen passen sauber in den ASCII-Zeichensatz, und die base64-Codierung ist daher eigentlich etwas sinnlos. Sie können es stattdessen mit in ASCII konvertieren

>>> encoded = 'data to be encoded'.encode('ascii')

Oder einfacher:

>>> encoded = b'data to be encoded'

Was in diesem Fall dasselbe wäre.


* Die meisten base64-Varianten können auch a = am Ende als Polsterung. Darüber hinaus können einige base64-Varianten andere Zeichen als verwenden + und /. Siehe die Übersichtstabelle der Varianten bei Wikipedia für einen Überblick.

  • “es will eine Zeichenfolge von 8-Bit-Bytes”. Ein Byte in einem Computer besteht aus 8 Bits und die meisten Datentypen in allen Programmiersprachen (einschließlich einer Python-Str) bestehen aus Bytes, daher verstehe ich nicht, was Sie damit meinen. Vielleicht “es will eine Zeichenfolge von 8-Bit-Zeichen” als ASCII-Zeichenfolge?

    – Alan Evangelista

    29. Juli 2021 um 11:49 Uhr


  • @AlanEvangelista Konzeptionell ist eine Python-Zeichenfolge eine Folge von Unicode-Zeichen. Es muss keine bestimmte zugrunde liegende binäre Darstellung haben. Andererseits ist A bytes oder bytearray Objekt repräsentiert tatsächlich eine Folge von Bytes/Oktetten. (Obwohl es auch keine bestimmte zugrunde liegende binäre Darstellung haben muss.)

    – Benutzer2846495

    23. August 2021 um 12:57 Uhr


Benutzer-Avatar
Gregor Schmitt

Kurze Antwort

Sie müssen a drücken bytes-like Objekt (bytes, bytearrayusw.) an die base64.b64encode() Methode. Hier sind zwei Möglichkeiten:

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

Oder mit einer Variablen:

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

Wieso den?

In Python3, str Objekte sind keine Zeichenarrays im C-Stil (also sind sie nicht Byte-Arrays), sondern sind Datenstrukturen, die keine inhärente Codierung haben. Sie können diese Zeichenfolge auf verschiedene Weise codieren (oder interpretieren). Das gebräuchlichste (und Standard in Python 3) ist utf-8, zumal es abwärtskompatibel mit ASCII ist (obwohl es die am weitesten verbreiteten Codierungen sind). Das passiert, wenn Sie eine nehmen string und ruf die an .encode() Methode darauf: Python interpretiert die Zeichenfolge in utf-8 (der Standardcodierung) und stellt Ihnen das Array von Bytes bereit, dem sie entspricht.

Base-64-Codierung in Python 3

Ursprünglich wurde im Titel der Frage nach der Base-64-Codierung gefragt. Lesen Sie weiter für Base-64-Sachen.

base64 Die Codierung nimmt 6-Bit-Binärblöcke und codiert sie mit den Zeichen AZ, az, 0-9, ‘+’, “https://stackoverflow.com/” und ‘=’ (einige Codierungen verwenden andere Zeichen anstelle von ‘ +’ und “https://stackoverflow.com/”). Dies ist eine Zeichencodierung, die auf dem mathematischen Konstrukt des Radix-64- oder Basis-64-Zahlensystems basiert, aber sie sind sehr unterschiedlich. Base-64 in Mathematik ist ein Zahlensystem wie binär oder dezimal, und Sie ändern die Basis für die gesamte Zahl oder (wenn die Basis, aus der Sie konvertieren, eine Potenz von 2 kleiner als 64 ist) in Blöcken von rechts nach links.

Im base64 Kodierung, die Übersetzung erfolgt von links nach rechts; Diese ersten 64 Zeichen sind der Grund für den Namen base64 Codierung. Das 65. ‘=’-Symbol wird zum Auffüllen verwendet, da die Codierung 6-Bit-Blöcke abruft, aber die Daten, die normalerweise codiert werden sollen, 8-Bit-Bytes sind, sodass manchmal nur zwei oder 4 Bits im letzten Abschnitt vorhanden sind.

Beispiel:

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

Wenn Sie diese Binärdaten als einzelne Ganzzahl interpretieren, dann würden Sie sie so in Basis-10 und Basis-64 umwandeln (Tabelle für Basis-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 Codierungwird diese Daten jedoch wie folgt neu gruppieren:

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’ ist also mathematisch gesehen die Base-64-Version unserer Binärdatei. Jedoch, base64 Codierung muss die Codierung in die entgegengesetzte Richtung machen (also die Rohdaten werden in ‘dGVzdA’ konvertiert) und hat auch eine Regel, die anderen Anwendungen mitteilt, wie viel Platz am Ende übrig bleibt. Dies geschieht, indem das Ende mit ‘=’-Symbolen aufgefüllt wird. Also, die base64 Die Codierung dieser Daten ist ‘dGVzdA==’, wobei zwei ‘=’-Symbole bedeuten, dass zwei Bitpaare am Ende entfernt werden müssen, wenn diese Daten decodiert werden, damit sie mit den Originaldaten übereinstimmen.

Lassen Sie uns das testen, um zu sehen, ob ich unehrlich bin:

>>> encoded = base64.b64encode(data)
>>> print(encoded)
b'dGVzdA=='

Warum verwenden base64 Codierung?

Nehmen wir an, ich muss einige Daten per E-Mail an jemanden senden, wie diese Daten:

>>> data = b'\x04\x6d\x73\x67\x08\x08\x08\x20\x20\x20'
>>> print(data.decode())
   
>>> print(data)
b'\x04msg\x08\x08\x08   '
>>>

Es gibt zwei Probleme, die ich gepflanzt habe:

  1. Wenn ich versuchte, diese E-Mail in Unix zu senden, wurde die E-Mail gesendet, sobald die \x04 Zeichen gelesen wurde, weil das für ASCII steht END-OF-TRANSMISSION (Strg-D), sodass die restlichen Daten bei der Übertragung weggelassen würden.
  2. Während Python schlau genug ist, all meinen bösen Steuerzeichen zu entkommen, wenn ich die Daten direkt drucke, können Sie sehen, dass die ‘msg’ nicht vorhanden ist, wenn diese Zeichenfolge als ASCII dekodiert wird. Das liegt daran, dass ich drei verwendet habe BACKSPACE Zeichen und drei SPACE Zeichen, um die ‘msg’ zu löschen. Also, auch wenn ich die nicht hatte EOF Zeichen dort wäre der Endbenutzer nicht in der Lage, den Text auf dem Bildschirm in die echten Rohdaten zu übersetzen.

Dies ist nur eine Demo, um Ihnen zu zeigen, wie schwierig es sein kann, einfach Rohdaten zu senden. Durch die Kodierung der Daten in das base64-Format erhalten Sie genau die gleichen Daten, jedoch in einem Format, das sicherstellt, dass sie sicher über elektronische Medien wie E-Mail gesendet werden können.

  • base64.b64encode(s.encode()).decode() ist nicht sehr pythonisch, wenn Sie nur eine String-zu-String-Konvertierung wünschen. base64.encode(s) sollte zumindest in python3 ausreichen. Vielen Dank für eine sehr gute Erklärung zu Strings und Bytes in Python

    – MortenB

    22. Februar 2018 um 9:53 Uhr

  • @MortenB Ja, es ist seltsam, aber auf der positiven Seite ist sehr klar, was passiert, solange der Ingenieur den Unterschied zwischen Arrays von Bytes und Zeichenfolgen kennt, da zwischen ihnen keine einzige Zuordnung (Codierung) wie in anderen Sprachen besteht davon ausgehen.

    – Gregor Schmitt

    22. Februar 2018 um 17:44 Uhr

  • @MortenB Übrigens base64.encode(s) würde in Python3 nicht funktionieren; meinst du sowas sollte es geben? Ich denke, der Grund, warum es verwirrend sein könnte, ist, dass je nach Codierung und Inhalt der Zeichenfolge s hat möglicherweise keine eindeutige Darstellung als Array von Bytes.

    – Gregor Schmitt

    22. Februar 2018 um 17:47 Uhr

  • Schmitt: Es war nur ein Beispiel dafür, wie einfach es sein sollte. die häufigsten Anwendungsfälle sollten so sein.

    – MortenB

    23. Februar 2018 um 18:41 Uhr

  • @MortenB, aber b64 ist nicht nur für Text gedacht, jeder binäre Inhalt kann b64-codiert werden (Audio, Bilder usw.). Wenn Sie es meiner Meinung nach so funktionieren lassen, wie Sie es vorschlagen, wird der Unterschied zwischen Text- und Byte-Array noch mehr ausgeblendet, was das Debuggen erschwert. Es verschiebt einfach die Schwierigkeit woanders hin.

    – Michael Ekoka

    2. Juni 2020 um 6:06 Uhr

Wenn die zu kodierenden Daten “exotische” Zeichen enthalten, müssen Sie meiner Meinung nach in “UTF-8” kodieren

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

Benutzer-Avatar
Alfredocambera

Wenn die Zeichenfolge Unicode ist, ist der einfachste Weg:

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

Es gibt alles, was Sie brauchen:

expected bytes, not str

Die Führung b macht Ihre Zeichenfolge binär.

Welche Python-Version verwendest du? 2.x oder 3.x?

Bearbeiten: Sehen http://docs.python.org/release/3.0.1/whatsnew/3.0.html#text-vs-data-anstatt-of-unicode-vs-8-bit für die blutigen Details von Strings in Python 3.x

  • Danke Ich benutze, 3.x. Warum will Python es explizit in Binär umwandeln? Dasselbe in Ruby wäre … erfordert > “base64” und dann > Base64.encode64 (‘zu codierende Daten’)

    – Dublintech

    18. Januar 2012 um 10:19 Uhr

  • @dublintech Weil sich (Unicode-) Text von Rohdaten unterscheidet. Wenn Sie eine Textzeichenfolge in Base64 codieren möchten, müssen Sie zuerst die Zeichencodierung (wie UTF-8) bestimmen, und dann haben Sie Bytes anstelle von Zeichen, die Sie in einer ascii-sicheren Textform codieren können.

    – Fortran

    18. Januar 2012 um 10:44 Uhr

  • Dies beantwortet die Frage nicht. Er weiß, dass es mit einem Bytes-Objekt funktioniert, aber nicht mit einem String-Objekt. Die Frage ist warum.

    – Lennart Regebro

    18. Januar 2012 um 13:32 Uhr

  • @fortran Die standardmäßige Python3-Zeichenfolgencodierung ist UTF, weiß nicht, warum sie explizit festgelegt werden muss.

    – xmedeko

    28. Juli 2016 um 12:03 Uhr

  • Danke Ich benutze, 3.x. Warum will Python es explizit in Binär umwandeln? Dasselbe in Ruby wäre … erfordert > “base64” und dann > Base64.encode64 (‘zu codierende Daten’)

    – Dublintech

    18. Januar 2012 um 10:19 Uhr

  • @dublintech Weil sich (Unicode-) Text von Rohdaten unterscheidet. Wenn Sie eine Textzeichenfolge in Base64 codieren möchten, müssen Sie zuerst die Zeichencodierung (wie UTF-8) bestimmen, und dann haben Sie Bytes anstelle von Zeichen, die Sie in einer ascii-sicheren Textform codieren können.

    – Fortran

    18. Januar 2012 um 10:44 Uhr

  • Dies beantwortet die Frage nicht. Er weiß, dass es mit einem Bytes-Objekt funktioniert, aber nicht mit einem String-Objekt. Die Frage ist warum.

    – Lennart Regebro

    18. Januar 2012 um 13:32 Uhr

  • @fortran Die standardmäßige Python3-Zeichenfolgencodierung ist UTF, weiß nicht, warum sie explizit festgelegt werden muss.

    – xmedeko

    28. Juli 2016 um 12:03 Uhr

1082620cookie-checkWarum brauche ich ‘b’, um eine Zeichenfolge mit Base64 zu codieren?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy