JSONstring中的二进制数据。 比Base64更好的东西

JSON格式本身不支持二进制数据。 二进制数据必须转义,以便它可以被放置到JSON中的string元素(即使用反斜杠转义的双引号中的零个或更多的Unicode字符)。

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

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

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

有没有更好的方法和标准的方法来编码二进制数据到JSONstring?

根据JSON规范(如果您的JSON以UTF-8发送),有94个Unicode字符可以表示为一个字节。 考虑到这一点,我认为你可以做的最好的空间是base85 ,代表四个字节为五个字符。 然而,这比base64只有7%的提高,计算起来更加昂贵,实现不如base64,所以它可能不是一个胜利。

您也可以简单地将每个input字节映射到U + 0000-U + 00FF中对应的字符,然后按JSON标准所要求的最小编码传递这些字符; 这里的优点是所要求的解码不在内build函数之外,但是空间效率很差 – 如果所有input字节可能性相同,则扩展为105%,base85为25%,base64为33%。

最终判决:在我看来,base64胜出的理由是,这是普遍的,容易的,并不够坏,不能更换。

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

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

这里有一个关于如何在obj-c中完成这个工作的很好的教程 ,下面是一篇博客文章 ,介绍如何使用表单边界对string数据进行分区,并将其与二进制数据分开。

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

当然,在服务器端需要额外的工作,但是如果你发送很多图像或大图像,这是值得的。 如果你愿意的话,可以把它与gzip压缩结合起来。

恕我直言,发送base64编码的数据是一个黑客; RFC multipart / form-data是针对以下问题创build的:将二进制数据与文本或元数据结合使用。

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

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

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

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

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

Base64编码仅增长到初始大小的133%。 所以Base64编码更有效率。

怎么样使用另一个基本编码? 在UTF-8中,编码128个ASCII值是空间效率最高的。 8位可以存储7位。 因此,如果我们以7位块的forms剪切二进制数据,将它们存储在UTF-8编码string的每个字节中,则编码后的数据只会增长到初始大小的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位块中切割input字节序列,对于这些块,简单的按位操作很好。 除了133%外,还不到122%。

这就是为什么我独立地得出了一个共同的结论:Base64确实是用JSON编码二进制数据的最佳select。 我的回答给出了一个理由。 我认为从性能的angular度来看它并不是很有吸引力,但是也要考虑使用JSON的好处,它的人类可读的string表示容易在所有编程语言中操作。

如果性能比纯二进制编码重要,则应该考虑replaceJSON。 但是对于JSON,我的结论是Base64是最好的。

yEnc可能会为你工作:

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

如果你处理带宽问题,首先尝试在客户端压缩数据,然后base64-it。

这个神奇的好例子是在http://jszip.stuartk.co.uk/和更多的讨论这个话题是在Gzip的JavaScript实现;

微笑格式

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

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

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

微笑编码的string可以在空间紧张的情况下进行压缩

尽pipebase64具有〜33%的扩展速率,但处理开销并不一定是这样:它实际上取决于您正在使用的JSON库/工具包。 编码和解码是简单直接的操作,甚至可以对字符编码进行优化(因为JSON只支持UTF-8/16/32) – 对于JSONstring条目,base64字符总是单字节。 例如,在Java平台上,有些库可以相当有效地完成这项工作,所以开销主要是由于扩展的大小。

我同意两个较早的答案:

  • base64是简单的,常用的标准,所以不可能find更好的与JSON一起使用的更好的东西(base-85被postscript等使用;但是当你考虑它时,好处是最好的)
  • 编码之前(以及解码之后)的压缩可能会有很大的意义,这取决于您使用的数据

由于您正在寻找将二进制数据严格限制为基于文本且格式非常有限的function,因此与您期望通过JSON维护的便利性相比,我认为Base64的开销很小。 如果处理能力和吞吐量是一个问题,那么你可能需要重新考虑你的文件格式。

编辑7年后: Google Gears消失了,忽略这个答案。)

Google Gears团队遇到了缺less二进制数据types的问题,并试图解决这个问题:

Blob API

JavaScript具有用于文本string的内置数据types,但对于二进制数据没有任何内容。 Blob对象试图解决这个限制。

也许你可以以某种方式编织。

只是为了增加讨论的资源和复杂性的立场。 由于做PUT / POST和PATCH来存储新资源并改变它们,应该记住,内容传输是存储的内容的准确表示,并且通过发出GET操作来接收。

多部分的消息通常被用作救世主,但是为了简单起见,对于更复杂的任务,我更喜欢把内容作为一个整体给出的想法。 这是自我解释,很简单。

而且是的JSON是瘫痪的东西,但最终JSON本身是冗长的。 而映射到BASE64的开销却很小。

正确使用多部分消息必须拆除要发送的对象,使用属性path作为自动组合的参数名称,或者需要创build另一个协议/格式来表示有效负载。

也喜欢BSON的方法,这不是那么广泛和容易支持,因为一个人会喜欢它。

基本上我们只是错过了一些东西,但是将二进制数据embedded到base64中已经很成熟了,除非您确定需要进行真正的二进制转换(这种情况通常不是这样)。

数据types真的关心。 我已经testing了从RESTful资源发送有效负载的不同场景。 对于编码,我使用了Base64(Apache)和压缩GZIP(java.utils.zip。*)。有效负载包含有关电影,图像和audio文件的信息。 我压缩和编码的图像和audio文件,大大降低了性能。 压缩之前的编码结果很好。 图像和audio内容作为编码和压缩字节[]发送。

请参阅: http : //snia.org/sites/default/files/Multi-part%20MIME%20Extension%20v1.0g.pdf

它描述了一种使用“CDMI内容types”操作在CDMI客户端和服务器之间传输二进制数据的方法,而不需要对二进制数据进行base64转换。

如果您可以使用“非CDMI内容types”操作,则将“数据”传送到对象是理想的。 随后,元数据可以作为后续的“CDMI内容types”操作被添加到/从对象中。

我的解决scheme现在,XHR2正在使用ArrayBuffer。 ArrayBuffer作为二进制序列包含多部分内容,video,audio,graphics,文本等多种内容types。 一切回应。

在现代浏览器中,为不同的组件提供DataView,StringView和Blob。 另请参阅: http : //rolfrost.de/video.html了解更多详情。