Pergunta

O JSON formato nativamente não suporta dados binários. Os dados binários deve ser escapado para que ele possa ser colocado em um elemento de string (ou seja, zero ou mais caracteres Unicode em aspas duplas usando escapes barra invertida) em JSON.

Um método óbvio para escapar de dados binários é usar Base64. No entanto, na base 64 tem uma sobrecarga de processamento elevada. Também se expande em 3 bytes 4 caracteres que leva a um aumento do tamanho dos dados por cerca de 33%.

Um caso de uso para isso é o projecto de v0.8 do CDMI armazenamento em nuvem especificação API . Você cria objetos de dados via REST-Webservice usando JSON, por exemplo.

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=",
}

Existem melhores formas e métodos padrão para codificar dados binários em cordas JSON?

Foi útil?

Solução

Existem 94 caracteres Unicode que podem ser representadas como um byte de acordo com a especificação JSON (se a sua JSON é transmitido como UTF-8). Com isso em mente, eu acho que o melhor que você pode fazer espaço-wise é base85 que representa quatro bytes como cinco caracteres. No entanto, esta é apenas uma melhoria de 7% em relação base64, é mais caro para computação, e implementações são menos comuns do que para base64 por isso provavelmente não é uma vitória.

Você também pode simplesmente mapear cada byte de entrada para o personagem correspondente em U + 0000-U + 00FF, em seguida, fazer o mínimo que codifica exigido pela norma JSON para passar esses personagens; A vantagem aqui é que a descodificação é necessário além nil incorporado funções, mas a eficiência de espaço é mau - uma expansão de 105% (se todos os bytes de entrada são igualmente provável) vs. 25% para base85 ou 33% de base 64

veredicto final:. Vitórias base64, na minha opinião, com base em que é comum, fácil, e não é mau o suficiente para substituição mandado

Veja também: Base91

Outras dicas

Eu corri para o mesmo problema, e pensei que iria partilhar uma solução:. multipart / form-data

Ao enviar um multipart formar você envia pela primeira vez como seqüência de sua meta-dados JSON , e em seguida, enviar separadamente como binário simples (imagem (s), wavs, etc) indexados pela Conteúdo -Disposition nome.

Aqui está uma boa tutorial sobre como fazer isso em obj-c, e aqui é um artigo no blog que explica como particionar os dados de cadeia com o limite forma, e separá-lo a partir dos dados binário.

A única mudança que você realmente precisa fazer é no lado do servidor; você terá que capturar seus meta-dados que deve referenciar os dados binários POST'ed adequadamente (usando um limite Content-Disposition).

Com certeza isso exige um trabalho adicional no lado do servidor, mas se você estiver enviando muitas imagens ou imagens grandes, este vale a pena. Combine isso com a compressão gzip, se quiser.

IMHO envio base64 dados codificados é um hack; as / form-data RFC várias partes foi criado para questões como esta:. envio de dados binários em combinação com texto ou meta-dados

BSON (Binary JSON) pode funcionar para você. http://en.wikipedia.org/wiki/BSON

Edit: FYI a biblioteca .NET json.net suportes de leitura e escrita bson se você está procurando um pouco de amor do lado do servidor C #.

O problema com UTF-8 é que ele não é o mais espaço codificação eficiente. Além disso, algumas sequências de bytes binários aleatórios são inválidos UTF-8. Então você não pode apenas interpretar uma seqüência de byte binário aleatório como alguns UTF-8 dados, pois será inválido codificação UTF-8. O benefício deste constrangimento na codificação UTF-8 é que ele torna mais robusto e possível localizar múltiplos caracteres de bytes início e fim tudo o byte que começar a olhar para.

Como uma consequência, se codifica para um valor de bytes no intervalo [0..127] seria necessário apenas um byte em UTF-8, que codifica para um valor de bytes no intervalo [128..255] exigiria 2 bytes! Pior do que isso. Em JSON, caracteres de controle, "e \ não estão autorizados a aparecer em uma string. Assim, os dados binários exigiria alguma transformação para ser devidamente codificado.

Vamos ver. Se assumirmos uniformemente distribuída valores de bytes aleatórios em nossos dados binários, em seguida, em média, metade dos bytes seria codificado em uma bytes ea outra metade em dois bytes. Os UTF-8 dados binários codificados teria 150% do tamanho inicial.

codificação base64 cresce apenas a 133% da dimensão inicial. Então codificação Base64 é mais eficiente.

Que tal usar outra codificação de Base? Em UTF-8, que codifica os valores ASCII 128 é o mais eficiente do espaço. Em 8 bits pode armazenar 7 bits. Portanto, se cortar os dados binários em bits 7 pedaços de armazená-los em cada byte de uma cadeia codificada UTF-8, os dados codificados iria crescer apenas a 114% da dimensão inicial. Melhor do que Base64. Infelizmente, não podemos usar esse truque fácil, porque JSON não permite que alguns caracteres ASCII. Os 33 caracteres de controle de ASCII ([0..31] e 127) e o "e \ deve ser excluída. Isso nos deixa apenas 128-35 = 93 caracteres.

Assim, em teoria, pode definir uma codificação Base93 que iria aumentar o tamanho codificada a 8 / log 2 (93) = 8 * log10 (2) / log 10 (93) = 122%. Mas uma codificação Base93 não seria tão conveniente como uma codificação Base64. Base64 requer para cortar a sequência de bytes de entrada em blocos 6Bit para que a operação simples bit a bit funciona bem. Ao lado de 133% não é muito mais do que 122%.

É por isso que eu vim independentemente à conclusão comum que Base64 é realmente a melhor escolha para codificar dados binários em JSON. Minha resposta apresenta uma justificação para isso. Concordo que não é muito atraente do ponto de vista do desempenho, mas considere também o benefício de usar JSON com a sua representação em cadeia legível fácil de manipular em todas as linguagens de programação.

Se o desempenho é crítico do que uma codificação binária pura deve ser considerado como substituto de JSON. Mas com JSON minha conclusão é que Base64 é o melhor.

Se você lidar com problemas de largura de banda, tentar Compactar dados no lado do cliente em primeiro lugar, em seguida, base64-lo.

Nice exemplo de tal magia está em http://jszip.stuartk.co.uk/ e mais discussão a este tópico é em JavaScript de Gzip

yEnc pode funcionar para você:

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

"yEnc é um esquema de codificação de binário para texto para a transferência de binário arquivos em [texto]. Ele reduz a sobrecarga sobre o anterior US-ASCII baseada- que codifica métodos usando um método ASCII que codifica estendido 8 bits. sobrecarga de yEnc é muitas vezes (se cada valor de byte aparece aproximadamente com a mesma frequência, em média) tão pouco quanto 1-2%, em comparação com 33% -40% de sobrecarga para 6 bits métodos como uuencode e na base 64 que codifica. ... Em 2003 yEnc tornou-se o sistema de codificação padrão de fato para arquivos binários de Usenet ".

No entanto, yEnc é uma codificação de 8 bits, então armazená-lo em uma string JSON tem os mesmos problemas que armazenar os dados binários originais -. Fazê-lo os meios maneira ingênuos sobre uma expansão de 100%, o que é pior do que base64

Sorriso formato

É muito rápido para codificar, descodificar e compacto

comparação Speed ??(java baseado mas significativa, no entanto): https://github.com/eishay/jvm-serializers/ wiki /

Também é uma extensão para JSON que permitem que você pule base64 codificação para matrizes de bytes

cordas Sorriso codificados podem ser compactado quando o espaço é crítico

Embora seja verdade que base64 tem ~ 33% taxa de expansão, não é necessariamente verdade que o processamento sobrecarga é significativamente mais do que isso: ele realmente depende de biblioteca JSON / kit de ferramentas que você está usando. Codificação e descodificação são operações direto simples, e que pode ainda ser optimizada de codificação de caracteres wrt (como JSON suporta apenas UTF-8/16/32) - base64 caracteres são sempre de byte único para entradas JSON corda. Por exemplo na plataforma Java existem bibliotecas que podem fazer o trabalho em vez de forma eficiente, de modo que a sobrecarga é principalmente devido ao tamanho expandido.

Concordo com duas respostas anteriores:

  • base64 é simples, padrão comumente utilizado, por isso é pouco provável que encontrar algo melhor especificamente para uso com JSON (base-85 é usada por posfácio etc, mas os benefícios são na melhor das hipóteses marginal quando você pensa sobre isso)
  • compressão antes de codificar (e após a decodificação) pode fazer muito sentido, dependendo dos dados que você usa

( Editar 7 anos mais tarde:.. Google Gears é ido Ignorar esta resposta)


O ran equipa Google Gears para o problema de falta de binário-data-tipos e tentou endereço lo:

Blob API

JavaScript tem um built-in tipo de dados para cadeias de texto, mas nada para dados binários. As tentativas objeto Blob para resolver esta limitação.

Talvez você pode tecer que, em alguma forma.

Uma vez que você está procurando a capacidade de calçadeira dados binários em um formato muito limitada estritamente baseada em texto e, eu acho que a sobrecarga de Base64 é mínima em comparação com a conveniência que você está esperando para manter com JSON. Se o poder de processamento e rendimento é uma preocupação, então você provavelmente terá que reconsiderar seus formatos de arquivo.

Apenas para adicionar o ponto de vista de recursos e complexidade para a discussão. Desde fazendo PUT / POST e PATCH para armazenar novos recursos e alterá-los, deve-se lembrar que a transferência de conteúdo é uma representação exata do conteúdo que é armazenado e que é recebido através da emissão de uma operação GET.

Uma mensagem multi-parte é usada frequentemente como um salvador, mas por razões de simplicidade e para tarefas mais complexas, eu prefiro a idéia de dar o conteúdo como um todo. É auto-explicativo e é simples.

E sim JSON é algo incapacitante, mas no final si JSON é detalhado. E a sobrecarga de mapeamento para BASE64 é uma maneira de pequeno porte.

Usando mensagens concatenadas corretamente um tem que quer desmantelar o objeto para enviar, usar um caminho de propriedade como o nome do parâmetro para a combinação automática ou será necessário criar um outro protocolo / formato apenas para expressar a carga útil.

Também gosto da abordagem BSON, isso não é tão ampla e facilmente suportado como gostaríamos que fosse.

Basicamente, nós apenas algo falta aqui, mas a incorporação de dados binários como base 64 está bem estabelecida e caminho a percorrer, a menos que você realmente tenha identificado a necessidade de fazer a transferência binário real (que dificilmente é frequentemente o caso).

Tipo de dados realmente preocupações. Eu testei diferentes cenários sobre o envio da carga útil de um recurso RESTful. Para codificar eu usei Base64 (Apache) e para a compressão GZIP (java.utils.zip. *). A carga contém informações sobre o filme, uma imagem e um arquivo de áudio. Tenho comprimido e codificado os arquivos de imagem e de áudio que degradadas drasticamente o desempenho. Codificação antes da compressão acabou bem. Imagem e conteúdo de áudio foram enviados como bytes codificados e comprimidos [].

Consulte: http: // SNIA. org / sites / default / files / multi-part% 20MIME% 20Extension% 20v1.0g.pdf

Ele descreve uma forma de transferir dados binários entre um cliente CDMI e servidor usando 'CDMI tipo de conteúdo' operações sem a necessidade de conversão base64 dos dados binário.

Se você pode usar a operação 'não-CDMI tipo de conteúdo', é ideal para a transferência de 'dados' para / de um objeto. Os metadados podem, posteriormente, ser adicionado / recuperados de / para o objeto como um 'tipo de conteúdo CDMI' operação subseqüente.

Se você estiver usando Nó, eu acho que a maneira mais eficiente e fácil é converter em UTF16 com:

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

Você pode buscar de volta os seus dados:

Buffer.from(s, 'utf16le');

Eu cavar um pouco mais (durante a implementação de base128 ), e expor que quando enviar caracteres que códigos ASCII são maiores do que 128, em seguida, navegador (Chrome) de fato enviar dois caracteres (bytes) em vez de um:. ( A razão é que JSON por personagens uso utf8 DEFAULT para as quais caracteres com códigos ASCII acima 127 são codificados por dois bytes que era menção por chmike resposta fiz teste da seguinte maneira:. digite chrome bar url chrome: // net-exportação / , selecione "Incluir bytes brutos", iniciar a captura, enviar solicitações POST (usando trecho na parte inferior), captura de parada e salve o arquivo JSON com solicita dados brutos. Então olhamos para dentro desse arquivo json :

  • Podemos encontrar nosso pedido base64 encontrando 4142434445464748494a4b4c4d4e corda esta é a codificação de ABCDEFGHIJKLMN hex e veremos que "byte_count": 639 para ele.
  • Podemos encontrar nosso pedido above127 encontrando C2BCC2BDC380C381C382C383C384C385C386C387C388C389C38AC38B corda isso são request-hex códigos utf8 de caracteres ¼½ÀÁÂÃÄÅÆÇÈÉÊË (no entanto os códigos ASCII hex desse personagens são c1c2c3c4c5c6c7c8c9cacbcccdce). O "byte_count": 703 por isso é 64bytes mais longos do que pedido base64 porque caracteres com códigos ASCII acima 127 são códigos de 2 bytes no pedido: (

Então, na verdade não temos lucro com o envio de caracteres com códigos> 127 :( Para base64 cordas que não observar tal comportamento negativo. (Provavelmente para base85 também - I don verificá-lo) - no entanto, pode haver alguma solução para isso problema será o envio de dados em parte binária do multipart / form-POST dados descritos no Ælex resposta (no entanto, normalmente, neste caso, não é necessário utilizar qualquer base de codificação em tudo ...).

A abordagem alternativa pode contar com mapeamento de dois bytes porção de dados em um caractere UTF-8 válida por código-lo usando algo como base65280 / base65k , mas provavelmente seria menos eficaz do que a base 64 devido a utf8 especificação ...

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>

A minha solução agora, XHR2 está usando ArrayBuffer. O ArrayBuffer como seqüência binária contém várias vias em conteúdo, vídeo, áudio, gráfico, texto e assim por diante com vários tipos de conteúdo. All in One Response.

No navegador moderno, tendo DataView, StringView e Blob para diferentes componentes. Veja também:. http://rolfrost.de/video.html para mais detalhes

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top