紧凑二进制表示的JSON

18

有没有一些紧凑的二进制 JSON 表示形式?我知道有BSON,但即使该网页上也说:“在许多情况下,它的效率与 JSON 差不多。在某些情况下,BSON 使用的空间甚至比 JSON 更多。”

我正在寻找一种尽可能紧凑的格式,最好是某种开放标准?


为什么不能在服务器上使用压缩? - Andrey
1
BSON规范在大小和效率方面都远非最佳选择。也许您应该考虑存储压缩的JSON(使用deflate或其他方法)。 - arthurprs
@Andrey,那可能是一个可行的解决方案,但我正在寻找一种减少我们向底层流提供数据量的方法(该流已经有一个选项可以实时压缩)。理论上,在对象编码级别进行压缩应该更容易,因为我们对标签等有上下文的了解。 - Shezan Baig
1
无论使用更紧凑的二进制格式,对于压缩来说,LZF都非常不错,因为它比gzip(deflate)更快地进行压缩,而且压缩比略低。 - StaxMan
1
MessagePack可以减少JSON的冗长性。http://msgpack.org - Christophe Morio
8个回答

16
你可以查看通用二进制JSON规范。它不像Smile那样紧凑,因为它不使用名称引用,但它与JSON完全兼容(而BSON和BJSON定义了在JSON中不存在的数据结构,因此没有标准的转换方式)。
它还有一个标准格式,阅读和编写非常简单:
[type, 1-byte char]([length, 4-byte int32])([data])

如此简单的数据类型以ASCII标记代码开头,例如32位整数为'I',true为'T',null为'Z',字符串为'S'等。
设计格式旨在快速读取,因为所有数据结构都带有其大小前缀,因此无需扫描空终止序列。
例如,读取可能像这样划分的字符串([]字符仅用于说明目的,不会写入格式中):
[S][512][this is a really long 512-byte UTF-8 string....]

你会看到一个'S',打开它以处理字符串,查看后面的4字节整数为"512",知道你可以一次性获取下一个512字节并将其解码回字符串。同样,数字值没有长度值而被写出来,以更紧凑的方式呈现,因为它们的类型(byte、int32、int64、double)都定义了它们的字节长度(分别为1、4、8和8)。还支持任意长的数字,这在不支持它们的平台上也非常便携。通常情况下,使用良好平衡的JSON对象(混合类型较多)可以看到大约30%的大小减小。如果您想确切地知道某些结构是如何压缩或不压缩的,可以查看Size Requirements部分以获得一个想法。好消息是,无论是否压缩,数据都将以更优化的格式编写,并且更快地处理。我今天检查了GitHub中读取/写入该格式的核心Input/OutputStream实现。我将在本周晚些时候检查一般基于反射的对象映射。您只需查看这两个类即可了解如何读取和写入格式,我认为核心逻辑大约为20行代码。这些类比较长,因为它们包括方法的抽象和一些结构,以检查标记字节以确保数据文件是有效格式等等。
如果您有非常具体的问题,比如规范的字节序(大端)或双精度数的数字格式(IEEE 754),所有这些都在规范文档中涵盖,或者直接问我。希望这可以帮到您!

1
太好了!解析很简单。速度很快。大小非常好。并且可以通过 tcpdump 来理解其表示(与 protobuf 的 varints 相反)。在简单的十六进制中,300 是 0x012C;在 UBJ 中,是 0x69012C(因为 0x69 是 ascii 的 i);在 protobuf 中,0xAC02 == 1010 1100 0000 0010。如果有负数,protobuf 的解析会变得更加困难(而且更慢)。Protobuf 不压缩字符串或浮点数,因此除非有许多小整数,否则大小相似,但 UBJ 很快,其解析器也很简单。 - cdunn2001
有任何公布的基准测试数据,关于速度方面的吗?现在所有的东西都很容易解析,你必须比较实现才能有任何真正速度的概念。 - StaxMan

10

是的: Smile 数据格式(请参见维基百科条目)具有公共的Java实现,在github上有C版本 (libsmile)。与JSON相比,它更紧凑(可靠地),但又是100%兼容逻辑数据模型,因此可以轻松地进行文本JSON之间的转换。

为了提高性能,您可以查看jvm-serializers基准测试,其中smile在与其他二进制格式(thrift、avro、protobuf)的竞争中表现良好;尺寸方面它不是最紧凑的(因为它保留字段名),但对于重复使用名称的数据流来说要好得多。

它正在被Elastic Search和Solr等项目使用(可选),Protostuff-rpc支持它,尽管它不像Thrift或protobuf那样广泛。

编辑(2011年12月)——现在还有PHP、Ruby和Python的libsmile绑定,因此语言支持正在改善。此外,还有关于数据大小的度量;虽然对于单记录数据,替代方案(Avro、protobuf)更紧凑,但对于数据流而言,由于可以使用键和字符串值的反向引用选项,Smile通常更紧凑。


微笑:尽管项目目标不同,但仍有奇怪的规格。 - arthurprs
@StaxMan,您可以提供Protostuff-rpc项目的链接吗? - Vladislav Rastrusny
@StaxMan,我在那里没有找到任何现成的RPC实现。你找到了吗?protostuff提供了编写自定义代码生成器以构建自己的RPC的能力。但似乎就只有这些了。 - Vladislav Rastrusny
嗯,我必须承认我没有使用过它,只是浏览了网页。但我知道它的作者非常乐于助人,也许可以直接联系他(David)?顺便说一句,喜欢你的昵称(曾经写过一个名为 Fractalizer 的 Java 应用程序) :) - StaxMan
链接失效了,第一个链接已经被吃掉了。 - Max Barraclough

4
gzipping JSON数据可以轻松获得良好的压缩比,因为它具有普遍支持。此外,如果您处于浏览器环境中,则可能会因为新库的依赖大小而付出更大的字节成本,而不是实际有效载荷的节省。
如果您的数据具有其他约束条件(例如大量冗余字段值),则可以通过查看不同的序列化协议来进行优化,而不是坚持使用JSON。例如:基于列的序列化,如Avro的即将推出的列存储,可能会为您提供更好的比率(用于磁盘存储)。如果您的有效载荷包含大量常量值(例如表示枚举的列),则词典压缩方法也可能很有用。

4

现在应该考虑的另一种选择是CBOR (RFC 7049),它具有明确的与JSON兼容的模型和很高的灵活性。它既稳定又符合您的开放标准要求,并且显然经过了很多思考。


很高兴看到一个真正的标准。谢谢建议! - Brad

1

0

0

目前你的回答不够清晰,请编辑并添加更多细节,以帮助其他人理解它如何回答问题。你可以在帮助中心找到有关如何编写好答案的更多信息。 - Community

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接