Frage

Der JSON-Format Unterstützt nativ keine Binärdaten.Die Binärdaten müssen maskiert werden, damit sie in ein String-Element eingefügt werden können (d. h.null oder mehr Unicode-Zeichen in doppelten Anführungszeichen mit Backslash-Escapezeichen) in JSON.

Eine naheliegende Methode zum Escapen von Binärdaten ist die Verwendung von Base64.Base64 hat jedoch einen hohen Verarbeitungsaufwand.Außerdem werden 3 Bytes auf 4 Zeichen erweitert, was zu einer um etwa 33 % erhöhten Datengröße führt.

Ein Anwendungsfall hierfür ist der v0.8-Entwurf des CDMI-Cloud-Speicher-API-Spezifikation.Sie erstellen Datenobjekte über einen REST-Webservice mit JSON, z.B.

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, Binärdaten in JSON-Strings zu kodieren?

War es hilfreich?

Lösung

Es gibt 94 Unicode-Zeichen, die als ein Byte nach der JSON-Spezifikation dargestellt werden können (wenn Ihr JSON als UTF-8 übertragen werden). In diesem Sinne, ich denke, das Beste, was Sie Raum weise tun können, base85 ist, die vier Byte repräsentiert als fünf Zeichen. Dies ist jedoch nur eine 7% ige Verbesserung gegenüber base64, es ist teurer zu berechnen, und Implementierungen sind weniger häufig als bei base64 so dass es wahrscheinlich nicht ein Gewinn ist.

Sie könnten auch einfach jedes Eingangsbyte auf das entsprechende Zeichen in U + 0000-U + 00FF Karte, dann tut die minimale Codierung durch den JSON-Standard erforderlich ist, um diese Zeichen übergeben; Der Vorteil hierbei ist, dass die erforderliche Decodierung nil über eingebaute Funktionen, aber die Raumeffizienz ist schlecht - a. 105% Expansion (wenn alle Eingangsbytes gleich wahrscheinlich) 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 rechtfertigen Ersatz

Siehe auch: Base91

Andere Tipps

Ich bin auf das gleiche Problem gestoßen und dachte, ich würde Ihnen eine Lösung mitteilen: Multipart-/Formulardaten.

Beim Senden eines mehrteiligen Formulars senden Sie zunächst Ihre Zeichenfolge JSON-Metadaten, und dann separat als rohe Binärdatei (Bilder, WAVs usw.) senden, die von der indiziert wird Inhaltliche Disposition Name.

Hier ist ein schönes Lernprogramm wie man das in obj-c macht, und hier ist ein Blogartikel Das erklärt, wie man die String-Daten mit der Formulargrenze partitioniert und von den Binärdaten trennt.

Die einzige Änderung, die Sie wirklich vornehmen müssen, erfolgt auf der Serverseite.Sie müssen Ihre Metadaten erfassen, die entsprechend auf die POST-Binärdaten verweisen sollten (unter Verwendung einer Content-Disposition-Grenze).

Zugegebenermaßen erfordert es zusätzlichen Aufwand auf der Serverseite, aber wenn Sie viele Bilder oder große Bilder versenden, lohnt sich das.Kombinieren Sie dies bei Bedarf mit der GZIP-Komprimierung.

Meiner Meinung nach ist das Senden von Base64-codierten Daten ein Hack;Die RFC-Multipart-/Formulardaten wurden für Probleme wie diese erstellt:Senden von Binärdaten in Kombination mit Text oder Metadaten.

BSON (Binary JSON) kann für Sie arbeiten. http://en.wikipedia.org/wiki/BSON

Edit: Zu Ihrer Information die .NET-Bibliothek json.net unterstützt das Lesen und Schreiben BSON wenn Sie für einige C # Server-Seite Liebe suchen.

Das Problem mit UTF-8 ist, dass es nicht der Raum eine effiziente Codierung ist. Auch sind einige zufälligen binären Bytefolgen ungültig UTF-8-Codierung. So können Sie nicht nur eine zufällige binäre Byte-Sequenz, wie einige UTF-8-Daten interpretieren, weil es ungültige UTF-8-Codierung sein wird. Der Vorteil dieser constrain auf der UTF-8-Codierung ist, dass sie es robust und ermöglicht Multi-Byte-Zeichen zu suchen beginnen und enden was auch immer Byte wir beginnen, an.

Als Folge, wenn ein Byte-Wert im Bereich kodiert [0..127] würde nur ein Byte in UTF-8-Codierung benötigen, codierend einen Byte-Wert im Bereich [128..255] würde 2 Bytes erfordern! Schlimmer als das. In JSON, Steuer Zeichen "und \ sind nicht zu erscheinen in einem String erlaubt. So werden die Binärdaten würden einige Transformation erfordern richtig codiert werden.

Lassen Sie uns sehen. Wenn wir gleichmäßig zufälligen Byte-Werte in unserer Binärdaten verteilt assume dann im Durchschnitt die Hälfte der Bytes würde in einem Byte und die andere Hälfte in zwei Bytes codiert werden. Die UTF-8-codierten Binärdaten würde 150% der ursprünglichen Größe haben.

Base64-Codierung wächst nur auf 133% der ursprünglichen Größe. So Base64-Codierung ist effizienter.

Was ist eine andere Base-Codierung? In UTF-8 Codierung der 128 ASCII-Werte ist der Raum effizient. In 8 Bits können Sie 7 Bits speichern. Wenn wir also die Binärdaten in 7-Bit-Stücke geschnitten, sie zu speichern, in jedem Byte eines UTF-8 kodierten String, würden die codierten Daten wachsen nur auf 114% der ursprünglichen Größe. Besser als Base64. Leider können wir nicht so einfach Trick verwenden, da JSON nicht einig ASCII-Zeichen erlaubt. Die 33 Steuerzeichen von ASCII ([0..31] und 127) und die "und \ ausgeschlossen werden müssen. Dies lässt uns nur 128-35 = 93 Zeichen.

Also in der Theorie könnten wir eine Base93-Codierung definieren, die die codierte Größe 8 / log2 wachsen würden (93) = 8 * log10 (2) / log10 (93) = 122%. Aber eine Base93-Codierung nicht so bequem als Base64-Codierung. Base64 erfordert die Eingangs-Byte-Sequenz in 6-Bit-Blöcken, für die einfache bitweise Operation funktioniert gut zu schneiden. Neben 133% ist nicht viel mehr als 122%.

Das ist, warum ich unabhängig zu dem gemeinsamen Schluss kam, dass Base64 ist in der Tat die beste Wahl binäre Daten in JSON zu kodieren. Meine Antwort stellt eine Rechtfertigung dafür. Ich stimme es nicht sehr attraktiv aus der Sicht der Performance, sondern berücksichtigen auch den Vorteil von JSON mit damit in allen Programmiersprachen Menschen lesbare String-Darstellung leicht zu manipulieren ist.

Wenn die Leistung kritisch ist als eine reine binäre Codierung sollte als Ersatz von JSON in Betracht gezogen werden. Aber mit JSON meine Schlussfolgerung ist, dass Base64 das Beste ist.

Wenn Sie mit einer Bandbreite von Problemen umgehen, versucht, Daten auf der Clientseite zu komprimieren zuerst, dann base64-it.

Schönes Beispiel für eine solche Magie ist unter http://jszip.stuartk.co.uk/ und Diskussion zu diesem Thema finden Sie unter JavaScript-Implementierung von gzip

yEnc könnte für Sie arbeiten:

http://en.wikipedia.org/wiki/Yenc

  

"yEnc ist ein Binär-Text-Codierungsschema für binäre Übertragung   Dateien in [Text]. Es reduziert den Aufwand im Vergleich zu früheren US-ASCII-basierten   Codierverfahren durch einen 8-Bit erweiterten ASCII-Codierverfahren verwendet wird.   yEnc Overhead ist oft (wenn jedes Byte erscheint ca.   mit der gleichen Frequenz im Durchschnitt) so wenig wie 1-2%, im Vergleich zu   33% -40% Overhead für die 6-Bit-Codierverfahren wie Uuencode und Base64.   ... Bis zum Jahr 2003 wurde yEnc die de-facto-Standard-Codiersystem für   Binär-Dateien im Usenet. "

es die naive Weise tun bedeutet ein etwa 100% Dehnung, die schlechter als Base64 ist <-

jedoch yEnc ist ein 8-Bit-Codierung, so dass es in einem JSON String speichert die gleichen Probleme wie die Speicherung der ursprünglichen binären Daten hat. / p>

Format Lächeln

Es ist sehr schnell zu kodieren, zu dekodieren und kompakt

Geschwindigkeitsvergleich (Java-basierte, aber sinnvoll dennoch): https://github.com/eishay/jvm-serializers/ wiki /

Auch ist es eine Erweiterung JSON, die Sie Base64-Codierung für Byte-Arrays

überspringen lassen

Lächeln kodierten Strings kann gzipped werden, wenn der Platz kritisch ist

Es stimmt zwar, dass Base64 hat ~ 33% Expansionsrate, ist es nicht unbedingt wahr, dass Overhead-Verarbeitung als dies deutlich: Es hängt wirklich von JSON-Bibliothek / Toolkit Sie verwenden. Codieren und Decodieren sind einfach geradlinig Operationen, und sie können sogar WRT Zeichencodierung optimiert werden (wie JSON nur UTF-8/16/32 unterstützt) - Base64 Figuren sind immer Einbyte- für JSON String Einträge. Zum Beispiel auf Java-Plattform gibt es Bibliotheken, die eher effizient die Arbeit erledigen können, so dass Overhead erweitert Größe meist zurückzuführen ist.

Ich bin mit zwei früheren Antworten:

  • base64 ist einfach, häufig verwendeter Standard, so ist es unwahrscheinlich, etwas besser gesagt mit JSON zu verwenden, finden (base-85 von Postscript usw. verwendet wird, aber Vorteile sind bestenfalls marginal, wenn man darüber nachdenkt)
  • Kompression vor der Codierung (und nach der Decodierung) kann viel Sinn machen, abhängig von Daten, die Sie verwenden

( Edit 7 Jahre später:.. Google Gears ist weg Ignorieren Sie diese Antwort)


Das Google Gears Team lief in die Mangel-of-Binär-Daten-Typen Problem und hat versucht, es zu lösen:

  

Blob API

     

JavaScript verfügt über einen eingebauten Datentyp für Text-Strings, aber nichts für binäre Daten. Das Blob-Objekt versucht, diese Einschränkung zu begegnen.

Vielleicht kann man das in irgendwie weben.

Da Sie für die Fähigkeit gesuchte Binärdaten in ein streng textbasierte und sehr begrenzten Format Schuhanzieher, ich glaube, Base64 Overhead minimal ist im Vergleich zu dem Komfort Sie erwarten, mit JSON zu halten. Wenn die Verarbeitungsleistung und Durchsatz ein Anliegen ist, dann würden Sie wahrscheinlich benötigen, um Ihre Dateiformate überdenken.

Nur die Ressource und die Komplexität Sicht auf die Diskussion hinzuzufügen. Da tut PUT / POST und PATCH für neue Ressourcen zu speichern und zu verändern sie, sollte man bedenken, dass die Übertragung von Inhalten ist eine exakte Darstellung des Inhalts, der gespeichert wird, und das wird durch die Ausgabe eine GET-Operation erhalten.

Eine mehrteilige Nachricht oft als Retter verwendet wird, aber der Einfachheit halber Grund und für komplexere Aufgaben, ziehe ich die Idee, den Inhalt als Ganzes zu geben. Es ist selbsterklärend und es ist einfach.

Und ja JSON ist etwas lähmend, aber am Ende JSON selbst ist ausführlich. Und der Aufwand der Zuordnung zu BASE64 ist eine Art und Weise zu klein ist.

Mit Multi-Part-Nachrichten richtig hat man entweder das Objekt demontieren, senden eine Eigenschaft Pfad als Parameternamen für die automatische Kombination verwenden oder benötigt ein anderes Protokoll / Format erstellen, um nur die Nutzlast auszudrücken.

Auch die BSON Ansatz zu mögen, dann ist dies nicht so weit und leicht unterstützt, wie man es möchte sein.

Im Grunde genommen, wir vermissen gerade hier etwas, aber binäre Daten Einbettung als base64 gut etabliert ist und Weg zu gehen, wenn Sie wirklich die Notwendigkeit erkannt haben, die reale binäre Übertragung (die kaum oft der Fall ist) zu tun.

Datentyp wirklich Sorgen. Ich habe auf das Senden der Nutzlast von einer RESTful Ressource verschiedenen Szenarien getestet. Für die Codierung habe ich Base64 (Apache) und für die Kompression verwendet GZIP (java.utils.zip. *). Die Nutzlast enthält Informationen über den Film, ein Bild und eine Audiodatei. Ich habe komprimiert und codiert die Bild- und Audiodateien, die drastisch die Leistung verschlechtert. Codierung vor der Kompression ist gut ausgegangen. Bild- und Audio-Inhalte wurden als codiertes und komprimiertes Bytes [] gesendet.

Siehe: http: // SNIA. org / sites / default / files / Mehrteiliger eiliger~~POS=HEADCOMP% 20MIME% 20Extension% 20v1.0g.pdf

Es beschreibt eine Möglichkeit, binäre Daten zwischen einem CDMI Client und Server mit ‚CDMI Inhaltstyp‘ Operationen zu übertragen, ohne Base64 Umwandlung der binären Daten erforderlich ist.

Wenn Sie ‚Nicht-CDMI Inhaltstyp‘ Betrieb verwenden können, ist es ideal ‚Daten‘ zu übertragen, zu / von einem Objekt. Metadaten können dann später hinzugefügt / abgerufen werden vom / zum Objekt als Folge ‚CDMI Inhaltstyp‘ Betrieb.

Wenn Sie Knoten verwenden, glaube ich, dass die effizienteste und einfache Art und Weise in UTF16 zu konvertieren ist mit:

Buffer.from(data).toString('utf16le');

Sie können Ihre Daten zurückholen durch:

Buffer.from(s, 'utf16le');

Ich grabe ein bisschen mehr (bei der Implementierung von base128 ) und belichten, dass , wenn wir Zeichen senden die ASCII-Codes sind größer als 128 dann Browser (Chrom) in der Tat zwei Zeichen senden (Byte) anstelle eines:. ( Der Grund dafür ist, dass JSON durch defaul Verwendung uTF8-Zeichen, für die Zeichen mit ASCII-Codes oberhalb 127 durch codiert werden zwei Bytes, was war die Rede von chmike Antwort, die ich gemacht Test auf diese Weise. Art in Chrom url bar chrome: // net-Export / , wählen Sie „Include rohes Bytes“, starten Sie die Erfassung, POST-Anfragen senden (snippet am Boden verwendet wird), stoppt die Erfassung und jSON-Datei mit rohen Daten anfordert speichern. Dann schauen wir in dieser jSON-Datei :

  • Wir können unsere base64 Anfrage finden von String 4142434445464748494a4b4c4d4e finden dies ist Hex-Codierung von ABCDEFGHIJKLMN und wir werden diese "byte_count": 639 für sie sehen.
  • Wir können unsere above127 Anfrage finden von String C2BCC2BDC380C381C382C383C384C385C386C387C388C389C38AC38B finden diese sind Anfrage-hex utf8 Codes von Zeichen ¼½ÀÁÂÃÄÅÆÇÈÉÊË (aber die ascii Hex-Codes dieser Zeichen sind c1c2c3c4c5c6c7c8c9cacbcccdce). Die "byte_count": 703 so ist es 64 Byte länger als base64 Anfrage weil Zeichen mit ASCII-Codes über 127 Code von 2 Bytes in Anforderung sind: (

So in der Tat profitieren wir haben nicht mit Zeichen mit Codes> 127 :( Für Base64-Strings zu senden wir nicht solche negativen Verhalten beobachten. (Wahrscheinlich für base85 auch - ich überprüfen, don es) - aber einige Lösung für dieses sein kann, Problem wird sein, Daten in binären Teil von POST multipart / form-data beschrieben in Senden Ælex (aber in der Regel in diesem Fall beantworten wir keine Basis-Codierung überhaupt verwenden müssen ...).

Der alternative Ansatz auf Mapping zwei Bytes Datenteil in ein gültigen UTF-8-Zeichen von Code verlassen kann es so etwas wie mit base65280 / base65k , aber wahrscheinlich wäre es weniger wirksam sein als base64 aufgrund UTF-8-Spezifikation ...

function postBase64() {
  let formData = new FormData();
  let req = new XMLHttpRequest();

  formData.append("base64ch", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/");
  req.open("POST", '/testBase64ch');
  req.send(formData);
}


function postAbove127() {
  let formData = new FormData();
  let req = new XMLHttpRequest();

  formData.append("above127", "¼½ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüý");
  req.open("POST", '/testAbove127');
  req.send(formData);
}
<button onclick=postBase64()>POST base64 chars</button>
<button onclick=postAbove127()>POST chars with codes>127</button>

Meine Lösung jetzt wird XHR2 Arraybuffer verwenden. Die Arraybuffer als binäre Sequenz enthält mehrt-Inhalte, Video, Audio, Grafik, Text und so weiter mit mehreren Content-Typen. All in One Antwort.

In der modernen Browser, mit Dataview, StringView und Blob für verschiedene Komponenten. Siehe auch:. http://rolfrost.de/video.html für weitere Details

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top