Das JSON-Format unterstützt nativ keine Binärdaten. Die Binärdaten müssen maskiert werden, damit sie in JSON in ein Zeichenfolgenelement (dh null oder mehr Unicode-Zeichen in doppelten Anführungszeichen mit umgekehrten Schrägstrichen) eingefügt werden können.
Eine naheliegende Methode, um Binärdaten zu umgehen, ist die Verwendung von Base64. Base64 hat jedoch einen hohen Verarbeitungsaufwand. Außerdem werden 3 Bytes in 4 Zeichen erweitert, was zu einer Erhöhung der Datengröße um etwa 33% führt.
Ein Anwendungsfall hierfür ist der Entwurf v0.8 der CDMI-Cloud-Speicher-API-Spezifikation . Sie erstellen Datenobjekte über einen REST-Webservice mit JSON, z
PUT /MyContainer/BinaryObject HTTP/1.1
Host: cloud.example.com
Accept: application/vnd.org.snia.cdmi.dataobject+json
Content-Type: application/vnd.org.snia.cdmi.dataobject+json
X-CDMI-Specification-Version: 1.0
{
"mimetype" : "application/octet-stream",
"metadata" : [ ],
"value" : "TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0aGlz
IHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaCBpcyBhIGx1c3Qgb2Yg
dGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodCBpbiB0aGUgY29udGlu
dWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZGdlLCBleGNlZWRzIHRo
ZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4=",
}
Gibt es bessere Möglichkeiten und Standardmethoden, um Binärdaten in JSON-Zeichenfolgen zu codieren?
JSON.parse
. B. usw. ......Antworten:
Es gibt 94 Unicode-Zeichen, die gemäß der JSON-Spezifikation als ein Byte dargestellt werden können (wenn Ihr JSON als UTF-8 übertragen wird). In diesem Sinne denke ich, dass das Beste, was Sie räumlich tun können, base85 ist, das vier Bytes als fünf Zeichen darstellt. Dies ist jedoch nur eine Verbesserung von 7% gegenüber base64, die Berechnung ist teurer und Implementierungen sind seltener als bei base64, sodass es wahrscheinlich kein Gewinn ist.
Sie können auch einfach jedes Eingabebyte dem entsprechenden Zeichen in U + 0000-U + 00FF zuordnen und dann die vom JSON-Standard erforderliche Mindestcodierung ausführen, um diese Zeichen zu übergeben. Der Vorteil hierbei ist, dass die erforderliche Decodierung nicht über die integrierten Funktionen hinausgeht, die Raumeffizienz jedoch schlecht ist - eine Erweiterung um 105% (wenn alle Eingangsbytes gleich wahrscheinlich sind) gegenüber 25% für base85 oder 33% für base64.
Endgültiges Urteil: base64 gewinnt meiner Meinung nach mit der Begründung, dass es üblich, einfach und nicht schlecht genug ist , um einen Ersatz zu rechtfertigen.
Siehe auch: Base91 und Base122
quelle
base64.b85encode()
undb85decode()
jetzt. Eine einfache Codierungs- / Decodierungs-Timing-Messung zeigt, dass b85 mehr als 13-mal langsamer als b64 ist. Wir haben also einen Größengewinn von 7%, aber einen Leistungsverlust von 1300%.DEL
als Steuerzeichen.Ich stieß auf dasselbe Problem und dachte, ich würde eine Lösung teilen: mehrteilige / Formulardaten.
Durch das Senden eines mehrteiligen Formulars senden Sie zuerst Ihre JSON-Metadaten als Zeichenfolge und dann separat als rohe Binärdatei (Bilder, Wellen usw.), die durch den Namen der Inhaltsdisposition indiziert ist .
Hier ist ein nettes Tutorial, wie dies in obj-c gemacht wird, und hier ist ein Blog-Artikel , in dem erklärt wird, wie die Zeichenfolgendaten mit der Formulargrenze partitioniert und von den Binärdaten getrennt werden.
Die einzige Änderung, die Sie wirklich vornehmen müssen, ist auf der Serverseite. Sie müssen Ihre Metadaten erfassen, die auf die POST-Binärdaten entsprechend verweisen sollten (unter Verwendung einer Content-Disposition-Grenze).
Zugegeben, es erfordert zusätzliche Arbeit auf der Serverseite, aber wenn Sie viele oder große Bilder senden, lohnt sich dies. Kombinieren Sie dies mit der gzip-Komprimierung, wenn Sie möchten.
IMHO ist das Senden von Base64-codierten Daten ein Hack; Die RFC-Multipart- / Formulardaten wurden für folgende Probleme erstellt: Senden von Binärdaten in Kombination mit Text oder Metadaten.
quelle
Das Problem mit UTF-8 ist, dass es nicht die platzsparendste Codierung ist. Einige zufällige binäre Byte-Sequenzen sind auch ungültig UTF-8-Codierung. Sie können eine zufällige binäre Byte-Sequenz also nicht einfach als UTF-8-Daten interpretieren, da dies eine ungültige UTF-8-Codierung ist. Der Vorteil dieser Einschränkung bei der UTF-8-Codierung besteht darin, dass es robust und möglich ist, Multi-Byte-Zeichen zu finden, die beginnen und enden, egal welches Byte wir betrachten.
Wenn für die Codierung eines Bytewerts im Bereich [0..127] nur ein Byte für die UTF-8-Codierung erforderlich wäre, wären für die Codierung eines Bytewerts im Bereich [128..255] 2 Bytes erforderlich! Schlimmer als das. In JSON dürfen die Steuerzeichen "und \ nicht in einer Zeichenfolge erscheinen. Daher müssten für die Binärdaten einige Transformationen ordnungsgemäß codiert werden.
Mal sehen. Wenn wir gleichmäßig verteilte zufällige Bytewerte in unseren Binärdaten annehmen, wird durchschnittlich die Hälfte der Bytes in einem Byte und die andere Hälfte in zwei Bytes codiert. Die UTF-8-codierten Binärdaten hätten 150% der ursprünglichen Größe.
Die Base64-Codierung wächst nur auf 133% der ursprünglichen Größe. Die Base64-Codierung ist also effizienter.
Was ist mit einer anderen Basiscodierung? In UTF-8 ist die Codierung der 128 ASCII-Werte am platzsparendsten. In 8 Bits können Sie 7 Bits speichern. Wenn wir also die Binärdaten in 7-Bit-Blöcke schneiden, um sie in jedem Byte einer UTF-8-codierten Zeichenfolge zu speichern, würden die codierten Daten nur auf 114% der ursprünglichen Größe anwachsen. Besser als Base64. Leider können wir diesen einfachen Trick nicht verwenden, da JSON einige ASCII-Zeichen nicht zulässt. Die 33 Steuerzeichen von ASCII ([0..31] und 127) und "und \" müssen ausgeschlossen werden. Dies lässt nur 128-35 = 93 Zeichen übrig.
Theoretisch könnten wir also eine Base93-Codierung definieren, die die codierte Größe auf 8 / log2 (93) = 8 * log10 (2) / log10 (93) = 122% erhöht. Eine Base93-Codierung wäre jedoch nicht so praktisch wie eine Base64-Codierung. Base64 muss die Eingangsbyte-Sequenz in 6-Bit-Blöcke schneiden, für die eine einfache bitweise Operation gut funktioniert. Neben 133% sind es nicht viel mehr als 122%.
Aus diesem Grund bin ich unabhängig zu dem allgemeinen Schluss gekommen, dass Base64 in der Tat die beste Wahl ist, um Binärdaten in JSON zu codieren. Meine Antwort ist eine Rechtfertigung dafür. Ich bin damit einverstanden, dass es aus Sicht der Leistung nicht sehr attraktiv ist, aber berücksichtigen Sie auch den Vorteil der Verwendung von JSON mit seiner von Menschen lesbaren Zeichenfolgendarstellung, die in allen Programmiersprachen leicht zu manipulieren ist.
Wenn die Leistung kritisch ist, sollte eine reine Binärcodierung als Ersatz für JSON betrachtet werden. Aber mit JSON ist meine Schlussfolgerung, dass Base64 das Beste ist.
quelle
BSON (Binary JSON) kann für Sie arbeiten. http://en.wikipedia.org/wiki/BSON
Bearbeiten: Zu Ihrer Information : Die .NET-Bibliothek json.net unterstützt das Lesen und Schreiben von bson, wenn Sie nach einer Liebe auf der C # -Serverseite suchen.
quelle
Wenn Sie mit Bandbreitenproblemen zu tun haben, versuchen Sie zuerst, Daten auf der Clientseite und dann auf base64-it zu komprimieren.
Ein gutes Beispiel für solche Magie finden Sie unter http://jszip.stuartk.co.uk/. Weitere Informationen zu diesem Thema finden Sie in der JavaScript-Implementierung von Gzip
quelle
Content-Encoding
) noch komprimieren können (und sollten ), da base64 ziemlich gut komprimiert.yEnc könnte für Sie arbeiten:
http://en.wikipedia.org/wiki/Yenc
YEnc ist jedoch eine 8-Bit-Codierung. Das Speichern in einer JSON-Zeichenfolge hat also die gleichen Probleme wie das Speichern der ursprünglichen Binärdaten. Wenn Sie dies auf naive Weise tun, bedeutet dies eine 100% ige Erweiterung, die schlechter als base64 ist.
quelle
Es stimmt zwar, dass base64 eine Expansionsrate von ~ 33% aufweist, aber es ist nicht unbedingt richtig, dass der Verarbeitungsaufwand erheblich höher ist: Dies hängt wirklich von der von Ihnen verwendeten JSON-Bibliothek / dem von Ihnen verwendeten Toolkit ab. Codierung und Decodierung sind einfache, unkomplizierte Operationen und können sogar für die Zeichencodierung optimiert werden (da JSON nur UTF-8/16/32 unterstützt) - base64-Zeichen sind für JSON-Zeichenfolgeneinträge immer Einzelbyte. Auf der Java-Plattform gibt es beispielsweise Bibliotheken, die die Arbeit ziemlich effizient erledigen können, sodass der Overhead hauptsächlich auf die erweiterte Größe zurückzuführen ist.
Ich stimme zwei früheren Antworten zu:
quelle
Lächeln-Format
Es ist sehr schnell zu kodieren, zu dekodieren und zu kompaktieren
Geschwindigkeitsvergleich (Java-basiert, aber dennoch aussagekräftig): https://github.com/eishay/jvm-serializers/wiki/
Es ist auch eine Erweiterung von JSON, mit der Sie die Base64-Codierung für Byte-Arrays überspringen können
Smile-codierte Zeichenfolgen können komprimiert werden, wenn der Speicherplatz kritisch ist
quelle
( 7 Jahre später bearbeiten: Google Gears ist weg. Ignorieren Sie diese Antwort.)
Das Google Gears-Team ist auf das Problem des Mangels an binären Datentypen gestoßen und hat versucht, es zu beheben:
Vielleicht kannst du das irgendwie einweben.
quelle
Da Sie nach der Möglichkeit suchen, Binärdaten in ein streng textbasiertes und sehr begrenztes Format umzuwandeln, ist der Overhead von Base64 meiner Meinung nach im Vergleich zu dem Komfort, den Sie mit JSON erwarten, minimal. Wenn Verarbeitungsleistung und Durchsatz ein Problem darstellen, müssen Sie wahrscheinlich Ihre Dateiformate überdenken.
quelle
Nur um der Diskussion den Ressourcen- und Komplexitätsstandpunkt hinzuzufügen. Da Sie PUT / POST und PATCH ausführen, um neue Ressourcen zu speichern und zu ändern, sollten Sie bedenken, dass die Inhaltsübertragung eine genaue Darstellung des Inhalts ist, der gespeichert wird und der durch Ausgeben einer GET-Operation empfangen wird.
Eine mehrteilige Nachricht wird oft als Retter verwendet, aber aus Gründen der Einfachheit und für komplexere Aufgaben bevorzuge ich die Idee, den Inhalt als Ganzes zu geben. Es ist selbsterklärend und einfach.
Und ja, JSON ist etwas Verkrüppelndes, aber am Ende ist JSON selbst ausführlich. Und der Aufwand für die Zuordnung zu BASE64 ist viel zu gering.
Wenn Sie mehrteilige Nachrichten korrekt verwenden, müssen Sie entweder das zu sendende Objekt zerlegen, einen Eigenschaftspfad als Parameternamen für die automatische Kombination verwenden oder ein anderes Protokoll / Format erstellen, um nur die Nutzdaten auszudrücken.
Auch der BSON-Ansatz ist nicht so weit verbreitet und einfach zu unterstützen, wie man es gerne hätte.
Grundsätzlich vermissen wir hier nur etwas, aber das Einbetten von Binärdaten als base64 ist gut etabliert und ein guter Weg, es sei denn, Sie haben wirklich die Notwendigkeit einer echten Binärübertragung erkannt (was selten der Fall ist).
quelle
Ich grabe ein bisschen mehr (während der Implementierung von base128 ) und stelle fest , dass wenn wir Zeichen senden, deren ASCII-Codes größer als 128 sind, der Browser (Chrome) tatsächlich ZWEI Zeichen (Bytes) anstelle von einem sendet :( . Der Grund ist, dass JSON Verwenden Sie standardmäßig utf8-Zeichen, für die Zeichen mit ASCII-Codes über 127 durch zwei Bytes codiert sind, was in der Antwort von chmike erwähnt wurde . Ich habe den Test folgendermaßen durchgeführt: Geben Sie chrome url bar chrome: // net-export / ein und wählen Sie "Include raw" Bytes ", starten Sie die Erfassung, senden Sie POST-Anforderungen (mithilfe des Snippets unten), beenden Sie die Erfassung und speichern Sie die JSON-Datei mit Rohanforderungsdaten. Dann schauen wir uns diese JSON-Datei an:
4142434445464748494a4b4c4d4e
dessen Hex-Codierung ist,ABCDEFGHIJKLMN
und wir werden das"byte_count": 639
dafür sehen.C2BCC2BDC380C381C382C383C384C385C386C387C388C389C38AC38B
Dies sind Request-Hex-Utf8-Codes von Zeichen¼½ÀÁÂÃÄÅÆÇÈÉÊË
(jedoch sind die ASCII-Hex-Codes dieser Zeichenc1c2c3c4c5c6c7c8c9cacbcccdce
). Das"byte_count": 703
ist also 64 Bytes länger als die Base64-Anfrage, da Zeichen mit ASCII-Codes über 127 in der Anfrage Code für 2 Bytes sind :(Tatsächlich haben wir also keinen Gewinn mit dem Senden von Zeichen mit Codes> 127 :(. Für base64-Zeichenfolgen beobachten wir kein derart negatives Verhalten (wahrscheinlich auch für base85 - ich überprüfe es nicht) - es kann jedoch eine Lösung für dieses Problem sein Senden von Daten im binären Teil der in Ælex answer beschriebenen POST-Multipart- / Formulardaten (in diesem Fall müssen wir jedoch normalerweise überhaupt keine Basiscodierung verwenden ...).
Der alternative Ansatz kann darauf beruhen, zwei Bytes Datenabschnitt in ein gültiges utf8-Zeichen abzubilden , indem er mit so etwas wie base65280 / base65k codiert wird, aber aufgrund der utf8-Spezifikation wäre er wahrscheinlich weniger effektiv als base64 ...
Code-Snippet anzeigen
quelle
Der Datentyp betrifft wirklich. Ich habe verschiedene Szenarien zum Senden der Nutzdaten von einer RESTful-Ressource getestet. Für die Codierung habe ich Base64 (Apache) und für die Komprimierung GZIP (java.utils.zip. *) Verwendet. Die Nutzdaten enthalten Informationen zu Film, Bild und Audiodatei. Ich habe die Bild- und Audiodateien komprimiert und codiert, was die Leistung drastisch verschlechterte. Die Codierung vor der Komprimierung verlief gut. Bild- und Audioinhalte wurden als codierte und komprimierte Bytes [] gesendet.
quelle
Siehe: http://snia.org/sites/default/files/Multi-part%20MIME%20Extension%20v1.0g.pdf
Es wird eine Möglichkeit beschrieben, Binärdaten zwischen einem CDMI-Client und -Server mithilfe von Operationen des Typs "CDMI-Inhaltstyp" zu übertragen, ohne dass die Binärdaten von base64 konvertiert werden müssen.
Wenn Sie die Operation "Nicht-CDMI-Inhaltstyp" verwenden können, ist es ideal, "Daten" zu / von einem Objekt zu übertragen. Metadaten können später als nachfolgende Operation 'CDMI-Inhaltstyp' zum / vom Objekt hinzugefügt / abgerufen werden.
quelle
Meine Lösung, XHR2, verwendet ArrayBuffer. Der ArrayBuffer als Binärsequenz enthält mehrteilige Inhalte, Video, Audio, Grafik, Text usw. mit mehreren Inhaltstypen. Alles in einer Antwort.
In modernen Browsern mit DataView, StringView und Blob für verschiedene Komponenten. Siehe auch: http://rolfrost.de/video.html für weitere Details.
quelle
[16, 2, 38, 89]
ist sehr ineffizient.