UTF-8的问题在于它不是最节省空间的编码。另外,一些随机的二进制字节序列是无效的UTF-8编码。因此,不能将随机的二进制字节序列解释为一些UTF-8数据,因为它将是无效的UTF-8编码。这种对UTF-8编码的约束的好处在于,它使定位多字节字符变得健壮,并且可以开始和结束我们开始看到的任何字节。
因此,如果对范围[0..127]中的字节值进行编码,在UTF-8编码中只需要一个字节,则对范围[128..255]中的字节值进行编码需要2个字节!比这更糟。在JSON中,控制字符"和不允许出现在字符串中。所以二进制数据需要一些转换才能正确编码。
让我们看看。如果我们假设二进制数据中的随机字节值是均匀分布的,那么平均来说,一半字节将被编码成一个字节,另一半则被编码成两个字节。UTF-8编码的二进制数据将有初始大小的150%。
base64编码只增长到初始大小的133%。所以base64编码更有效。
使用另一种基本编码怎么样?在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。
Yenc可能为您工作:
然而,Yenc是一种8位编码,因此将其存储在JSON字符串中与存储原始二进制数据有相同的问题—是不是使用NA?ve-way意味着大约100%的扩展,这比base64更糟糕。
编码、解码和压缩都很快
它也是JSON的扩展,允许您跳过字节数组的base64编码。
当空间很关键时,可以对微笑编码的字符串进行gzip处理。
虽然base64的扩展率约为33%,但处理开销不一定比这高出很多:它实际上取决于您使用的JSON库/工具箱。编码和解码是简单的直接操作,甚至可以优化WRT字符编码(因为JSON只支持UTF-8/16/32)——对于JSON字符串条目,base64字符总是单字节的。例如,在Java平台上,有一些库可以高效地完成工作,因此开销很大程度上是由于扩展的大小。
- base64是一种简单、常用的标准,因此不太可能找到更好的专门与JSON一起使用的标准(base 85由PostScript等使用;但是当您考虑它时,好处最好是微乎其微的)。
- 根据所使用的数据,编码前(和解码后)的压缩可能很有意义。
(7年后编辑:GoogleGears消失了。忽略此答案。)
Google Gears团队遇到了缺乏二进制数据类型的问题,并试图解决它:
也许你可以用某种方法把它编织起来。
由于您正在寻找将二进制数据转换为严格基于文本且非常有限的格式的能力,我认为与您期望使用JSON维护的便利性相比,base64的开销是最小的。如果处理能力和吞吐量是一个问题,那么您可能需要重新考虑您的文件格式。
只是为了在讨论中添加资源和复杂性的观点。由于执行了存储新资源并对其进行修改的Put/Post和Patch操作,因此应该记住,内容传输是存储内容的精确表示,并通过发出get操作接收这些内容。
多部分消息通常被用作救世主,但出于简单的原因和更复杂的任务,我更喜欢将内容作为一个整体提供。这是自我解释,而且很简单。
是的,JSON是一个严重的问题,但最终JSON本身是冗长的。映射到base64的开销很小。
正确地使用多部分消息,要么拆除要发送的对象,使用属性路径作为参数名进行自动组合,要么需要创建另一个协议/格式来表示有效负载。
同样喜欢BSON方法,这并不像人们希望的那样广泛和容易支持。
基本上,我们在这里遗漏了一些东西,但是将二进制数据嵌入base64已经很好地建立起来了,而且还有很长的路要走,除非您确实确定需要执行真正的二进制传输(这种情况很少发生)。
我更深入地挖掘了一点(在base128的实现过程中),揭示了当我们发送ASCII码大于128的字符时,浏览器(chrome)实际上发送了两个字符(字节),而不是一个:()。原因是,json通过defaul使用了utf8字符,其中ASCII代码高于127的字符由chmike answer提到的两个字节编码。我用这种方式进行了测试:键入chrome url bar
-
703因此它比base64请求长64字节,因为ASCII代码高于127的字符在请求中的代码是2字节:(
所以事实上,发送代码大于127的字符是没有利润的:(。对于base64字符串,我们没有观察到这样的负面行为(可能对base85也是如此-我不检查它)-但是,对于这个问题,可能有一些解决方案将以二进制形式发送数据,该二进制部分是后多部分/表单数据,如中所述?lex应答(不过通常在这种情况下,我们根本不需要使用任何基本编码…)。
另一种方法可能依赖于使用类似base65280/base65k的代码将两个字节的数据部分映射为一个有效的utf8字符,但由于utf8规范的原因,它可能不如base64有效…
它描述了一种使用"cdmi content type"操作在cdmi客户机和服务器之间传输二进制数据的方法,而不需要对二进制数据进行base64转换。
如果您可以使用"非cdmi内容类型"操作,则最好将"数据"传输到对象或从对象传输。然后可以将元数据作为后续的"cdmi内容类型"操作添加/检索到对象或从对象中检索元数据。
如果您使用的是node,我认为最有效和最简单的方法是使用以下代码转换成utf16:
您可以通过以下方式取回数据:
数据类型确实令人担忧。我已经测试了从RESTful资源发送有效负载的不同场景。对于编码,我使用了Base64(Apache)和压缩Gzip(Java.UTL.zip)。有效载荷包含关于胶片、图像和音频文件的信息。我压缩和编码了图像和音频文件,这大大降低了性能。压缩前的编码效果很好。图像和音频内容以编码和压缩字节[]的形式发送。
我的解决方案是xhr2使用arraybuffer。arrayBuffer作为二进制序列包含多部分内容、视频、音频、图形、文本等,具有多种内容类型。一应俱全。
在现代浏览器中,为不同的组件提供数据视图、字符串视图和BLOB。有关详细信息,请参阅:http://rolfrost.de/video.html。