Das Problem mit UTF-8 ist, dass es nicht die platzsparendste Kodierung ist. Außerdem sind einige zufällige binäre Bytefolgen in der UTF-8-Kodierung ungültig. Man kann also nicht einfach eine zufällige binäre Bytefolge als UTF-8-Daten interpretieren, weil sie eine ungültige UTF-8-Kodierung ist. Der Vorteil dieser Einschränkung der UTF-8-Kodierung besteht darin, dass sie robust ist und es möglich macht, Mehrbyte-Zeichen am Anfang und am Ende zu lokalisieren, unabhängig davon, welches Byte wir zu Beginn betrachten.
Dies hat zur Folge, dass die Kodierung eines Byte-Wertes im Bereich [0..127] bei der UTF-8-Kodierung nur ein Byte benötigt, während die Kodierung eines Byte-Wertes im Bereich [128..255] 2 Bytes erfordert! Und es kommt noch schlimmer. In JSON dürfen Steuerzeichen, " und \ nicht in einer Zeichenfolge erscheinen. Die binären Daten müssten also umgewandelt werden, um richtig kodiert zu werden.
Mal sehen. Wenn wir von gleichmäßig verteilten, zufälligen Byte-Werten in unseren Binärdaten ausgehen, würde im Durchschnitt die Hälfte der Bytes in einem Byte und die andere Hälfte in zwei Bytes kodiert werden. Die UTF-8-kodierten Binärdaten hätten dann 150 % der ursprünglichen Größe.
Die Base64-Kodierung wächst nur auf 133 % der ursprünglichen Größe. Die Base64-Kodierung ist also effizienter.
Wie wäre es mit der Verwendung einer anderen Base-Kodierung? In UTF-8 ist die Kodierung der 128 ASCII-Werte am platzsparendsten. In 8 Bits können Sie 7 Bits speichern. Wenn wir also die binären Daten in 7-Bit-Stücke zerschneiden, um sie in jedem Byte einer UTF-8-kodierten Zeichenfolge zu speichern, würden die kodierten Daten nur auf 114 % der ursprünglichen Größe anwachsen. Besser als Base64. Leider können wir diesen einfachen Trick nicht anwenden, da JSON einige ASCII-Zeichen nicht zulässt. Die 33 Steuerzeichen von ASCII ( [0..31] und 127) und die " und \ müssen ausgeschlossen werden. Damit bleiben uns nur 128-35 = 93 Zeichen.
Theoretisch könnten wir also eine Base93-Kodierung definieren, die die kodierte Größe auf 8/log2(93) = 8*log10(2)/log10(93) = 122% erhöhen würde. Aber eine Base93-Kodierung wäre nicht so praktisch wie eine Base64-Kodierung. Bei Base64 muss die eingegebene Bytefolge in 6-Bit-Blöcke zerlegt werden, wofür eine einfache bitweise Operation gut geeignet ist. Außerdem ist 133% nicht viel mehr als 122%.
Deshalb bin ich unabhängig davon zu dem gemeinsamen Schluss gekommen, dass Base64 tatsächlich die beste Wahl für die Kodierung von Binärdaten in JSON ist. Meine Antwort enthält eine Rechtfertigung dafür. Ich stimme zu, dass es aus Sicht der Leistung nicht sehr attraktiv ist, aber bedenken Sie auch den Vorteil der Verwendung von JSON mit seiner menschenlesbaren Zeichenkettendarstellung, die in allen Programmiersprachen leicht zu bearbeiten ist.
Wenn die Leistung entscheidend ist, sollte eine rein binäre Kodierung als Ersatz für JSON in Betracht gezogen werden. Aber mit JSON ist meine Schlussfolgerung, dass Base64 die beste ist.
51 Stimmen
Für den Upload: Sie machen es nur einmal, also ist es keine große Sache. Für den Download: Sie werden überrascht sein, wie gut base64 komprimiert unter gzip Wenn Sie also gzip auf Ihrem Server aktiviert haben, ist das wahrscheinlich auch in Ordnung.
6 Stimmen
Eine weitere würdige Lösung msgpack.org für die Hardcore-Nerds: github.com/msgpack/msgpack/blob/master/spec.md
6 Stimmen
@cloudfeet, Einmal pro Benutzer pro Aktion . Eine sehr große Sache.
8 Stimmen
Beachten Sie, dass die Zeichen in der Regel 2 Bytes Speicher jede. So könnte base64 +33% (4/3) Overhead auf der Leitung verursachen, aber die Daten auf die Leitung zu bringen, sie abzurufen und zu nutzen, würde erfordern eine +166%ige (8/3) Overhead . Ein Beispiel: Wenn eine Javascript-Zeichenkette eine maximale Länge von 100k Zeichen hat, können Sie mit base64 nur 37,5k Bytes an Daten darstellen, nicht 75k Bytes an Daten. Diese Zahlen können in vielen Teilen der Anwendung einen Engpass darstellen, z. B.
JSON.parse
usw. ......0 Stimmen
....... Diese Zahlen stehen im Gegensatz zu den Einsparungen, die Sie erzielen können, wenn Sie die binären Rohdaten in Codepoints konvertieren und diese Codepoints dann in UTF-8 umwandeln. Selbst eine einfache Konvertierung unter Verwendung der Kodierung für Codepoints
0x00
a0xff
würde sich im Durchschnitt ein Aufwand von nur +50%) . und ................0 Stimmen
................. Konvertierung unter Verwendung der Kodierung für Codepoints
0x00
a0xffff
ergibt sich ein durchschnittlicher Overhead von ~48.5% . Konvertierung unter Verwendung der Kodierung für Codepoints0x00
a0x10ffff
im Durchschnitt zu Gemeinkosten von 39.8% . Das sind 71,5k Bytes an Daten, die Sie mit 100k Zeichen darstellen können, anstatt der 37,5k Bytes von base64.11 Stimmen
@Pacerier "typischerweise 2 Byte Speicher [pro Zeichen]" ist nicht korrekt. v8 hat zum Beispiel OneByte und TwoByte Strings. Zwei-Byte-Zeichenfolgen werden nur dort verwendet, wo es notwendig ist, um einen grotesken Speicherverbrauch zu vermeiden. Base64 ist mit Ein-Byte-Zeichenfolgen kodierbar.