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

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

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

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标准来传递这些字符所需的最小编码;这里的优点是,所要求的解码是nil超出内建函数,但空间效率差 - 一个105%膨胀(如果所有输入的字节是等可能的)与对于base85 25%或为BASE64 33%

终审判决:BASE64胜,在我看来,其理由是它是常见的,容易的,而不是坏的足够的,以保证更换

参见: Base91

其他提示

我遇到了同样的问题,并想分享一个解决方案: 多部分/表单数据。

通过发送多部分表单,您首先作为字符串发送 JSON 元数据, ,然后分别作为原始二进制文件(图像、wav 等)发送,由 内容处置 姓名。

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

您真正需要做的唯一更改是在服务器端;您必须捕获元数据,该元数据应适当地引用 POST 后的二进制数据(通过使用内容处置边界)。

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

恕我直言,发送 Base64 编码数据是一种 hack;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编码是更有效的。

关于使用另一个基本编码什么?以UTF-8,编码128个ASCII值是最有效的空间。在8位可以存储7位。因此,如果我们切二进制数据在7位的块将它们存储在一个UTF-8编码的字符串的每个字节中,编码的数据将增长的初始大小的仅114%。比Base64的更好。不幸的是,因为JSON不允许一些ASCII字符,我们不能用这种简单的伎俩。 ASCII的33个控制字符([0..31]和127)和“和\必须被排除。这使我们仅128-35 = 93个字符。

因此,在理论上,我们可以定义一个Base93编码这将生长所编码的大小设置为8 / LOG2(93)= 8 *日志10(2)/日志10(93)= 122%。但Base93编码不会为Base64编码的方便。 Base64的要求削减在6位块输入字节序列,其简单的位运算效果很好。除了133%是不是远远超过122%。

这就是为什么我单独来到了共同的结论是Base64是确实以JSON编码的二进制数据的最佳选择。我的回答提出了它的理由。我同意这是不是从性能上来看非常有吸引力,也可以考虑使用JSON与它的人类可读的字符串表示易于所有的编程语言来操纵的利益。

如果性能是至关重要的比纯二进制编码应被视为替代JSON的。但随着JSON我的结论是,Base64是最好的。

如果您处理带宽问题,尝试在客户端先压缩数据,然后基于64位吧。

的这种魔尼斯实例是在 http://jszip.stuartk.co.uk/ 并且,以获取更多的讨论是在 JavaScript实现Gzip已

yEnc可能会为你工作:

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

  

“yEnc是用于传输二进制的二进制到文本编码方案   在[文字]文件。它减少了以前的开销US-ASCII为主   编码方法通过使用一个8位扩展ASCII编码方法。   yEnc的开销常常是(如果每个字节的值大约出现   与平均相同的频率)低至1-2%,相比   33%-40%的开销为6位的编码方法等UUENCODE和Base64的。   ......到2003年yEnc成为事实上的标准编码系统   在Usenet二进制文件“。

然而,yEnc是一个8位的编码,因此将其存储在JSON串具有相同的问题存储原始二进制数据 - 这样做的简单的方式是指约100%的膨胀,其比BASE64更糟<。 / p>

微笑格式

这是非常快速的编码,解码和小型

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

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

当空间是关键的

微笑编码的字符串可以gzip压缩

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

我同意之前的两个答案:

  • base64 是简单、常用的标准,因此不太可能找到更好的专门用于 JSON 的东西(base-85 由 postscript 等使用;但当你考虑一下时,好处充其量是微不足道的)
  • 编码前(和解码后)压缩可能很有意义,具体取决于您使用的数据

修改7年后:谷歌齿轮被忽略了这个答案)


在谷歌齿轮队跑进缺的二进制数据类型的问题,并试图解决它:

  

<强> 斑点API

     

JavaScript有一个内置的二进制数据文本字符串数据类型,但一无所获。 Blob对象试图解决了这一限制。

也许你可以编织,在某种程度上。

由于你正在寻找鞋拔子二进制数据到一个严格的基于文本的,非常有限的格式的能力,我觉得比起你希望使用JSON维护方便Base64编码的开销最小。如果处理能力和吞吐量是一个问题,那么你可能需要重新考虑你的文件格式。

只是为了资源和复杂性的角度来看加入到讨论中。因为这样做PUT / POST和PATCH用于存储新的资源和改变他们,应该记住的是,内容传送是存储内容的确切表示,并且通过发出GET操作接收。

一个多部分消息被经常用作救星但是为了简单的原因和用于更复杂的任务,我更喜欢的给出了内容作为一个整体的思想。它是自我解释,这是简单的。

和JSON是东西瘫痪,但最终JSON本身很冗长。和映射到BASE64的开销是一种能够小。

使用多部分消息正确地一个已要么拆除对象发送,使用一个属性路径作为自动组合参数名称或将需要创建另一个协议/格式只是表达的有效负载。

另外喜欢的BSON方法,这不是广泛且容易地支持作为一个想的那样。

基本上,我们只是错过这里的东西,但嵌入二进制数据为base64是公认的和路可走,除非你真的确定需要做真正的二进制传输(这几乎是经常发生的情况)。

数据类型真正的担忧。我已经从一个RESTful资源发送有效载荷测试不同的场景。用于编码我已经使用的Base64(Apache)的和用于压缩GZIP(java.utils.zip。*)。该有效载荷包含关于电影,图像和音频文件的信息。我已经压缩和编码这大大降低性能的图像和音频文件。压缩编码前横空出世很好。图像和音频内容被送往作为编码和压缩的字节[]。

参见: HTTP:// SNIA。组织/站点/默认/文件/多零件%20MIME%20Extension%20v1.0g.pdf

它描述的方式,而不需要二进制数据的转换的base64传输使用“CDMI内容类型”动作的CDMI客户端和服务器之间的二进制数据。

如果可以使用“非CDMI内容类型”操作,理想的是从一个物体传送“数据”到/。元数据可以再后来被添加/检索到/从对象作为后续“CDMI内容类型”操作。

如果您使用的节点,我认为,最有效,最简单的方法是转换成具有UTF16:

Buffer.from(data).toString('utf16le');

您可以通过接回你的数据:

Buffer.from(s, 'utf16le');

我挖掘得更多一点(在实施期间 基数128),并揭露 当我们发送 ASCII 码大于 128 的字符时,浏览器(chrome)实际上发送两个字符(字节)而不是一个:(. 。原因是 JSON 默认使用 utf8 字符,其中 127 以上的 ASCII 代码的字符由两个字节编码,如前面提到的 奇麦克 回答。我是这样进行测试的:在 chrome 网址栏中输入 chrome://net-export/ ,选择“包含原始字节”,开始捕获,发送 POST 请求(使用底部的代码片段),停止捕获并保存包含原始请求数据的 json 文件。然后我们查看该 json 文件:

  • 我们可以通过查找字符串来找到我们的base64请求 4142434445464748494a4b4c4d4e 这是十六进制编码 ABCDEFGHIJKLMN 我们将会看到 "byte_count": 639 为了它。
  • 我们可以通过查找字符串找到我们的above127请求 C2BCC2BDC380C381C382C383C384C385C386C387C388C389C38AC38B 这是请求十六进制 utf8 字符代码 ¼½ÀÁÂÃÄÅÆÇÈÉÊË (但是这个字符的 ascii 十六进制代码是 c1c2c3c4c5c6c7c8c9cacbcccdce)。这 "byte_count": 703 所以它比base64请求长64字节,因为ascii代码高于127的字符在请求中按2字节编码:(

所以事实上我们发送代码 >127 :( 的字符并没有什么好处。对于base64字符串,我们没有观察到这种负面行为(可能对于base85也是如此 - 我不检查它) - 但是这个问题的一些解决方案可能是在 POST multipart/form-data 中描述的二进制部分中发送数据 埃莱克斯回答 (但是通常在这种情况下我们根本不需要使用任何基本编码......)。

另一种方法可能依赖于使用类似的代码将两个字节数据部分映射到一个有效的 utf8 字符 基数65280 / 基数65k 但由于以下原因,它可能不如 Base64 有效 utf8规范 ...

function postBase64() {
  let formData = new FormData();
  let req = new XMLHttpRequest();

  formData.append("base64ch", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/");
  req.open("POST", '/testBase64ch');
  req.send(formData);
}


function postAbove127() {
  let formData = new FormData();
  let req = new XMLHttpRequest();

  formData.append("above127", "¼½ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüý");
  req.open("POST", '/testAbove127');
  req.send(formData);
}
<button onclick=postBase64()>POST base64 chars</button>
<button onclick=postAbove127()>POST chars with codes>127</button>

我的解决办法,现在,XHR2使用ArrayBuffer。该ArrayBuffer二进制序列包含多部分内容,视频,音频,图片,文字等与多个内容类型。所有在一个响应中。

在现代浏览器,具有数据视图,StringView和斑点为不同的部件。 参见:。 http://rolfrost.de/video.html 了解细节

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top