该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字符串?
根据JSON规范,有94个Unicode字符可以表示为一个字节(如果您的JSON以UTF-8格式传输).考虑到这一点,我认为你可以在空间方面做的最好的是base85,它代表四个字节作为五个字符.然而,这比base64仅提高了7%,计算成本更高,并且实现不如base64那么常见,因此它可能不是一个胜利.
您也可以简单地将每个输入字节映射到U + 0000-U + 00FF中的相应字符,然后执行JSON标准所要求的最小编码来传递这些字符; 这里的优点是所需的解码不超过内置函数,但空间效率很差 - 105%扩展(如果所有输入字节都相同),而base85为25%,base64为33%.
最终判决:在我看来,base64胜出,理由是它是常见的,简单的,并且不足以保证更换.
另见:Base91
我知道这是一个将近6年的问题,但我遇到了同样的问题,并认为我会分享一个解决方案:multipart/form-data.
通过发送多部分表单,您首先将您的JSON元数据作为字符串发送,然后分别发送为由Content-Disposition名称索引的原始二进制文件(图像,wavs等).
这是一个关于如何在obj-c中执行此操作的精彩教程,这是一篇博客文章,解释了如何使用表单边界对字符串数据进行分区,并将其与二进制数据分开.
您真正需要做的唯一改变是在服务器端; 你必须捕获你的元数据,它应该适当地引用POST的二进制数据(通过使用Content-Disposition边界).
当然,它需要在服务器端进行额外的工作,但如果您要发送许多图像或大图像,这是值得的.如果需要,可以将其与gzip压缩相结合.
恕我直言,发送base64编码数据是一个黑客; 为这样的问题创建了RFC multipart/form-data:结合文本或元数据发送二进制数据.
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中,控制字符"和\"不允许出现在字符串中.因此二进制数据需要进行一些转换才能正确编码.
让我们看看.如果我们假设在我们的二进制数据中均匀分布的随机字节值,那么平均来说,一半字节将在一个字节中编码,另一半在两个字节中编码.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是最好的.
如果您处理带宽问题,请先尝试在客户端压缩数据,然后再使用base64-it.
这种魔术的好例子是http://jszip.stuartk.co.uk/,关于这个主题的更多讨论是在Gzip的JavaScript实现
yEnc可能适合你:
http://en.wikipedia.org/wiki/Yenc
微笑格式
编码,解码和压缩速度非常快
速度比较(基于java但有意义):https://github.com/eishay/jvm-serializers/wiki/
它也是JSON的扩展,允许您跳过字节数组的base64编码
当空间很关键时,可以对微笑编码的字符串进行压缩
虽然base64确实具有~33%的扩展速率,但是处理开销并不一定比这更明显:它实际上取决于您正在使用的JSON库/工具包.编码和解码是简单的直接操作,甚至可以通过字符编码进行优化(因为JSON仅支持UTF-8/16/32) - 对于JSON字符串条目,base64字符始终是单字节.例如,在Java平台上,有些库可以相当高效地完成工作,因此开销主要是由于扩展的大小.
我同意两个早先的答案:
base64是简单的,常用的标准,因此不太可能找到更好的特别用于JSON的东西(posts-etc使用base-85;但是当你考虑它时,好处是最好的边缘)
编码前(和解码后)压缩可能会有很大意义,具体取决于您使用的数据