当前位置:  开发笔记 > 编程语言 > 正文

JSON字符串中的二进制数据.比Base64更好的东西

如何解决《JSON字符串中的二进制数据.比Base64更好的东西》经验,为你挑选了8个好方法。

该JSON格式本身不支持二进制数据.必须对二进制数据进行转义,以便可以将其放入JSON中的字符串元素(即使用反斜杠转义的双引号中的零个或多个Unicode字符).

转义二进制数据的一个明显方法是使用Base64.但是,Base64具有很高的处理开销.它还将3个字节扩展为4个字符,从而使数据量增加了大约33%.

一个用例是CDMI云存储API规范的v0.8草案.您可以使用JSON通过REST-Webservice创建数据对象,例如

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

是否有更好的方法和标准方法将二进制数据编码为JSON字符串?



1> hobbs..:

根据JSON规范,有94个Unicode字符可以表示为一个字节(如果您的JSON以UTF-8格式传输).考虑到这一点,我认为你可以在空间方面做的最好的是base85,它代表四个字节作为五个字符.然而,这比base64仅提高了7%,计算成本更高,并且实现不如base64那么常见,因此它可能不是一个胜利.

您也可以简单地将每个输入字节映射到U + 0000-U + 00FF中的相应字符,然后执行JSON标准所要求的最小编码来传递这些字符; 这里的优点是所需的解码不超过内置函数,但空间效率很差 - 105%扩展(如果所有输入字节都相同),而base85为25%,base64为33%.

最终判决:在我看来,base64胜出,理由是它是常见的,简单的,并且不足以保证更换.

另见:Base91


Python 3.4现在包含`base64.b85encode()`和`b85decode()`.简单的编码+解码时序测量表明,b85比b64慢13倍.所以我们获得了7%的胜利,但是性能损失了1300%.
Base91对于JSON来说是个坏主意,因为它包含字母表中的引号.在最坏的情况下(所有引号输出)在JSON编码之后,它是原始有效载荷的245%.
等一下如何使用实际字节编码引号字符105%扩展和base64只有33%?是不是base64 133%?
@hobbs [JSON](http://json.org/)声明必须转义控制字符.[RFC20第5.2节](https://tools.ietf.org/html/rfc20)将`DEL`定义为控制字符.
@Tino ECMA-404专门列出了需要转义的字符:双引号U + 0022,反斜杠U + 005C和"控制字符U + 0000到U + 001F".

2> Ælex..:

我知道这是一个将近6年的问题,但我遇到了同样的问题,并认为我会分享一个解决方案:multipart/form-data.

通过发送多部分表单,您首先将您的JSON元数据作为字符串发送,然后分别发送为由Content-Disposition名称索引的原始二进制文件(图像,wavs等).

这是一个关于如何在obj-c中执行此操作的精彩教程,这是一篇博客文章,解释了如何使用表单边界对字符串数据进行分区,并将其与二进制数据分开.

您真正需要做的唯一改变是在服务器端; 你必须捕获你的元数据,它应该适当地引用POST的二进制数据(通过使用Content-Disposition边界).

当然,它需要在服务器端进行额外的工作,但如果您要发送许多图像或大图像,这是值得的.如果需要,可以将其与gzip压缩相结合.

恕我直言,发送base64编码数据是一个黑客; 为这样的问题创建了RFC multipart/form-data:结合文本或元数据发送二进制数据.


顺便说一下,Google Drive API正是以这种方式实现的:https://developers.google.com/drive/v2/reference/files/update#examples
@ t3chb0t multipart/form-data媒体类型诞生于传输表单数据,但今天它在HTTP/HTML世界之外被广泛使用,特别是对电子邮件内容进行编码.今天,它被提议作为通用编码语法.https://tools.ietf.org/html/rfc7578
_sending base64编码数据是一个hack_,因此是multipart/form-data.即使您链接的博客文章也会使用您声明的Content-Type multipart/form-data读取_By,您发送的内容实际上是一个表单.但事实并非如此.所以我认为base64 hack不仅更容易实现而且更可靠_我已经看到了一些库(例如Python),它们具有硬编码的multipart/form-data内容类型.
为什么在使用本机特征而不是尝试将圆形(二进制)栓塞入正方形(ASCII)孔时,此答案如此之低?...
@MarkKCowan可能是因为虽然这对问题的目的有所帮助,但它并未回答所提出的问题,实际上是“在JSON中使用文本编码的开销较低的二进制文件”,因此此答案完全可以解决JSON问题。

3> DarcyThomas..:

BSON(二进制JSON)可能适合您. http://en.wikipedia.org/wiki/BSON

编辑:FYI .NET库json.net支持读写bson,如果你正在寻找一些C#服务器端爱.



4> chmike..:

UTF-8的问题在于它不是最节省空间的编码.此外,一些随机二进制字节序列是无效的UTF-8编码.因此,您不能将随机二进制字节序列解释为某些UTF-8数据,因为它将是无效的UTF-8编码.这种对UTF-8编码的约束的好处在于它使得它很可靠并且可以定位多字节字符开始和结束我们开始查看的任何字节.

因此,如果在[0..127]范围内编码字节值只需要UTF-8编码中的一个字节,则编码[128..255]范围内的字节值将需要2个字节!比那更糟糕.在JSON中,控制字符"和\"不允许出现在字符串中.因此二进制数据需要进行一些转换才能正确编码.

让我们看看.如果我们假设在我们的二进制数据中均匀分布的随机字节值,那么平均来说,一半字节将在一个字节中编码,另一半在两个字节中编码.UTF-8编码的二进制数据将具有初始大小的150%.

Base64编码仅增长到初始大小的133%.因此Base64编码效率更高.

那么使用其他Base编码呢?在UTF-8中,对128个ASCII值进行编码是最节省空间的.在8位中,您可以存储7位.因此,如果我们以7位块的形式剪切二进制数据以将它们存储在UTF-8编码字符串的每个字节中,则编码数据将仅增长到初始大小的114%.比Base64好.不幸的是,我们不能使用这个简单的技巧,因为JSON不允许一些ASCII字符.ASCII([0..31]和127)的33个控制字符和"和\"必须被排除.这使得我们只有128-35 = 93个字符.

因此理论上我们可以定义一个Base93编码,它将编码大小增加到8/log2(93)= 8*log10(2)/ log10(93)= 122%.但Base93编码不如Base64编码方便.Base64需要以6位块的形式切割输入字节序列,以便简单的按位运算.除133%外,不超过122%.

这就是我独立得出的结论,即Base64确实是用JSON编码二进制数据的最佳选择.我的答案提出了理由.我同意从性能的角度来看它并不是很吸引人,但也要考虑使用JSON的好处,它的人类可读字符串表示易于在所有编程语言中操作.

如果性能至关重要,则应将纯二进制编码视为JSON的替代.但是对于JSON,我的结论是Base64是最好的.



5> andrej..:

如果您处理带宽问题,请先尝试在客户端压缩数据,然后再使用base64-it.

这种魔术的好例子是http://jszip.stuartk.co.uk/,关于这个主题的更多讨论是在Gzip的JavaScript实现


这是一个声称性能更好的JavaScript zip实现:[zip.js](http://gildas-lormeau.github.com/zip.js/)

6> richardtalle..:

yEnc可能适合你:

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


由于很多人似乎仍然在看这个问题,我想提一下,我不认为yEnc在这里真的有帮助.yEnc是一个8位编码,因此将其存储在JSON字符串中与存储原始二进制数据具有相同的问题 - 以天真的方式执行它意味着100%的扩展,这比base64更糟糕.

7> 小智..:

微笑格式

编码,解码和压缩速度非常快

速度比较(基于java但有意义):https://github.com/eishay/jvm-serializers/wiki/

它也是JSON的扩展,允许您跳过字节数组的base64编码

当空间很关键时,可以对微笑编码的字符串进行压缩


......而且链接已经死了.这个似乎是最新的:https://github.com/FasterXML/smile-format-specification

8> StaxMan..:

虽然base64确实具有~33%的扩展速率,但是处理开销并不一定比这更明显:它实际上取决于您正在使用的JSON库/工具包.编码和解码是简单的直接操作,甚至可以通过字符编码进行优化(因为JSON仅支持UTF-8/16/32) - 对于JSON字符串条目,base64字符始终是单字节.例如,在Java平台上,有些库可以相当高效地完成工作,因此开销主要是由于扩展的大小.

我同意两个早先的答案:

base64是简单的,常用的标准,因此不太可能找到更好的特别用于JSON的东西(posts-etc使用base-85;但是当你考虑它时,好处是最好的边缘)

编码前(和解码后)压缩可能会有很大意义,具体取决于您使用的数据

推荐阅读
php
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有