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

转义二进制数据的一个明显方法是使用Base64。然而,Base64有很高的处理开销。此外,它将3个字节扩展为4个字符,导致数据大小增加约33%。

其中一个用例是CDMI云存储API规范的0.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字符串?


当前回答

在讨论中加入资源和复杂性的观点。由于使用PUT/POST和PATCH来存储和修改新资源,所以应该记住,内容传输是通过发出GET操作来存储和接收的内容的精确表示。

多部分信息通常被用作救星,但出于简单的原因和更复杂的任务,我更喜欢将内容作为一个整体来提供。它是不言自明的,而且很简单。

JSON确实很麻烦,但最终JSON本身也很冗长。而且映射到BASE64的开销也很小。

正确使用Multi-Part消息,必须拆除要发送的对象,使用属性路径作为自动组合的参数名称,或者需要创建另一种协议/格式来表达有效负载。

同样喜欢BSON方法,这并不像人们所希望的那样被广泛和容易支持。

基本上,我们在这里漏掉了一些东西,但是将二进制数据嵌入为base64是很好的方法,除非您确实确定需要进行真正的二进制传输(这很少是这样的情况)。

其他回答

(7年后编辑:谷歌Gears消失了。忽略这个答案。)


谷歌Gears团队遇到了缺少二进制数据类型的问题,并试图解决它:

Blob API JavaScript为文本字符串提供了内置的数据类型,但没有用于二进制数据的数据类型。Blob对象试图解决这个限制。

也许你可以想办法编进去。

根据JSON规范,有94个Unicode字符可以表示为一个字节(如果您的JSON以UTF-8传输)。考虑到这一点,我认为最好的空格方式是base85,它将四个字节表示为五个字符。然而,这只比base64提高了7%,它的计算成本更高,实现也不像base64那么常见,所以它可能不是一个胜利。

您还可以简单地将每个输入字节映射到U+0000-U+00FF中的相应字符,然后执行JSON标准所需的最小编码来传递这些字符;这里的优点是,除了内置函数之外,所需的解码为nil,但空间效率很差——105%的扩展(如果所有输入字节的可能性相等),而base85为25%,base64为33%。

最终结论:在我看来,base64胜出,因为它是常见的、简单的,而且还没有坏到需要替换的地步。

参见:Base91和Base122

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

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

只是添加另一个选项,我们低级的恐龙程序员使用……

一种老式的方法是Intel HEX格式,这种方法已经存在了三年了。它建立于1973年,UNIX时代开始于1970年1月1日。

它的效率更高吗?不。 这是一个公认的标准吗?是的。 它是否像JSON那样适合人类阅读?是的,而且比大多数二进制解决方案更具可读性。

json看起来像这样:

{
    "data": [
    ":10010000214601360121470136007EFE09D2190140",
    ":100110002146017E17C20001FF5F16002148011928",
    ":10012000194E79234623965778239EDA3F01B2CAA7",
    ":100130003F0156702B5E712B722B732146013421C7",
    ":00000001FF"
    ]
}

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