一直以为对JSON所有的语法都了如指掌,毕竟json的标准用一只手都数的过来,直到我发现了一个叫ndJSON的标准,简单说,以下2种语法都是合法的:

图一:json格式

图二:ndjson格式

其中图一是常见的json格式,而且整个json对象是一个列表:元素由逗号分隔,再由方括号闭合。图二则是一种称为ndJSON的格式,由换行符(0x0A)分隔每个json对象,最外面也没有闭合字符对。ndjson的mime类型是application/x-ndjson。

需要注意的是,图一和图二并不等同,就是说,图一和图二不仅使用了不同的序列化格式,数据所表达的含义也是不同的。图一只表达了一个对象:一个列表,图二则表达了3个对象:3个“data”字典。这个区别是json和ndjson的本质区别。

NDJSON(ndjson.org)

ndjson(New-line Delimited JSON)是一个比较新的标准,本身超简单,就是一个.ndjson文件中,每行都是一个传统json对象,当然每个json对象中要去掉原本用于格式化的换行符,而json的string中本身就不允许出现换行符(取而代之的是\n),所以ndjson在语法上基本不会出现歧义。但现在问题来了,ndjson有什么用?

JSON流问题(https://en.wikipedia.org/wiki/JSON_streaming)

新的标准总是来自于新的需求。ndjson的出现起源于json流问题。当时,我在设计一个方法用于将mongodb数据库的一张表备份到一个文件中,由于涉及到3个端的数据传输而没有对数据做整体处理的需求,就得使用管道流了。

其实流的概念非常简单,所有的数据传输都是流,都需要把大的数据分割成若干小份然后依次传输,只不过大多情况下传输都是通过底下的api自动完成的,我们感受不到“分割”的过程,也很难感受到“管道传输”的过程。正是这种底层的屏蔽造成了我们的无知,当要我们亲自设计管道的时候就嗝屁了。

在上面这个跨3端管道传输数据流的任务中,需要一边序列化一边走管道,最合适的做法就是将整张表格分割成一个个json对象(无论是sql还是mongo,表中的每一行都可以看成一个json对象),然后通过主机管道流向文件系统。这里出现了一个问题,数据流的最终存在形式是什么?是一个json文件吗?不可能,因为json文件只能表示一个json对象,而数据库表中有若干个对象。那给mysql表中的每一行保存一份json文件?好像也不合适。

HACK JSON

勉强的方法是使用一个json文件存放一份超长的json列表来收纳每一行数据。之所以勉强是因为构造一个json列表需要一些hack技巧:一开始需要写一个‘[’,中间每个json对象之间需要写‘,’,传输完成后又需要一个‘]’,所以我的代码是这样的:

fsWriter.write('[')
dbReader.on('data', rowObj => {fsWriter.write(JSON.stringify(rowObj));fsWriter.write(',');
});
dbReader.on('close', () => {// 由于json不允许在最后一个列表元素后面加逗号,hack一个空字典fsWriter.write('{}]');fsWriter.end();
});

只能说,hack一时爽,一直hack一直爽,天天hack火葬场。通过hack来达到目的是有后遗症的,容易给你带来一堆麻烦事。假如我想在json文件最后插入一条记录或者读取一条记录怎么办?json是作为一个整体来编译处理的,想要读取其中的某一部分也得先编译整个json对象。这是json设计上的一个缺陷,即整体无法直接分割,当然如果你想hack json的话我也不拦你,只是如果想要实现一个通用的方法就得重新设计json流的格式了。带着这个疑问,我想起了程序员3大错觉之一的“我超越了标准库”,于是在维基百科上查了一下原来真的有json流格式。

如图,维基百科介绍了4种不同的json流解决方案,其中第一种就是本文一开始讲到的ndjson,即使用换行符分割的json,由于换行符的特殊性,不会出现歧义:

{"some":"thing\n"}
{"may":{"include":"nested","objects":["and","arrays\n"]}}

ndjson和第二种解决方案比较相似,第二种是通过2个更特殊的控制字符来分割(确切的说是包裹)每一个独立对象,这两个字符是记录分隔符<RS>和行尾反馈符<LF>,这种解决方案利用这2个我前所未闻的控制字符来包裹每个json对象,颇有点超文本标记语言的感觉:

<RS>{"some":"thing"}<LF>
<RS>{"may": {"include": "nested","objects": ["and","arrays"]}
}<LF>

图中第三种和第四种方案我就不推荐啦,第三种是不要分隔符,前后2个对象直接相连:

{"some":"thing\n"}{"may":{"include":"nested","objects":["and","arrays"]}}

第四种模仿二进制格式,将对象长度写在前缀里:

18{"some":"thing\n"}55{"may":{"include":"nested","objects":["and","arrays"]}}

这两种方案不仅长相丑陋,而且还容易引起歧义,强烈不推荐使用,而且4种方案中也只有第一种的ndjson实现了标准化,它也是最常用的。当然,这4种都是文本格式的流解决方案,在二进制流领域中问题就简单得多了,比如message pack对象的长度就写在前缀中,对象之后可以直接拼接下一个对象而不会出现任何歧义,就像刚刚的方案三一样。

最后总结一下ndjson对json的性能提升:ndjson使整个文件“流化”,或者说把整个文件分割成许多份,这样避免了整体的束缚,支持局部处理,变得更灵活更快,从而实现了序列化和流传输的同时进行。

参考链接

https://jimmy.blog.csdn.net/article/details/90678160

https://medium.com/@kandros/newline-delimited-json-is-awesome-8f6259ed4b4b

http://ndjson.org/

https://github.com/ndjson/ndjson-spec

你所不知道的ndJSON:序列化与管道流相关推荐

  1. python可以引流吗_python能干嘛?你所不知道的Python有趣用途(上)

    前言 很多人都觉得Python虽然好学,但却不晓得如何将其应用到生活中,或是只知道Python可以拿来做「数据分析」.「爬虫」.甚至是「人工智慧」,但却觉得那些东西离自己很遥远 (尤其是初学者,经常会 ...

  2. 你所不知道的日志异步落库

    https://www.cnblogs.com/scy251147/p/9193075.html 在互联网设计架构过程中,日志异步落库,俨然已经是高并发环节中不可缺少的一环.为什么说是高并发环节中不可 ...

  3. Android Context完全解析,你所不知道的Context的各种细节

    转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/47028975 前几篇文章,我也是费劲心思写了一个ListView系列的三部曲,虽然 ...

  4. 【即构 Web SDK 开发团队】FLV音画同步 — 你所不知道的 SEI

    即构 Web SDK 开发团队 的文章深入分析了SEI和 HJPlayer 的使用: 音画同步 - 你所不知道的 SEI HJPlayer 同时支持hls flv srs player 拉flv流显示 ...

  5. 魂斗罗java设计,你所不知道的《魂斗罗》 设计企划书告诉你神作如何炼成

    你所不知道的<魂斗罗> 设计企划书告诉你神作如何炼成 2016-08-09 18:07:59来源:游戏下载编辑:评论(0) 很多人对电子游戏最初的记忆里都不会少了<魂斗罗>,但 ...

  6. 你所不知道的C和C++运行库

    你所不知道的C和C++运行库 周五晚,小雨,少见的未加班.无聊,遂准备写一篇博客,介绍一下C和C++运行库,只因发现工作几年的人对此一知半解的大有人在. 在使用VC构建项目时,经常会遇到下面的链接错误 ...

  7. 那些你所不知道的arXiv使用技巧

    作者:Tom Hardy Date:2020-12-23 来源:那些你所不知道的arXiv使用技巧

  8. 系统调优,你所不知道的TIME_WAIT和CLOSE_WAIT

    https://my.oschina.net/fdhay/blog/638631 高性能网络 | 你所不知道的TIME_WAIT和CLOSE_WAIT 2016-02-18 大房 大房说 本文是我将最 ...

  9. ai的弹窗点了都不响应_【评价集合】拼多多评价,你所不知道的点都在这里!...

    对于在拼多多开店的商家们来说,评价是消费者对于商品的好坏程度的一个评分,评价的高低不仅仅会影响到商品的销量,更会影响转化率以及权重!所以为了店铺商品的长远发展打算!各位商家在求取出评.好评的道路上不断 ...

最新文章

  1. 新年新技术:MongoDB 3.0
  2. 应该始终以PreparedStatement代替Statement
  3. 构建之法第四章读后感
  4. LeetCode-剑指 Offer 18. 删除链表的节点
  5. 天锐绿盾解密_天锐绿盾携手衡阳规划设计院 实现信息系统安全管理
  6. [C/C++基础知识] 那些被遗忘的链表知识
  7. 1024 科学计数法 (20 分
  8. python列表内元素求和_在Python中将列表的每个元素与另一个列表的每个元素相乘/相加/相除的有效方法...
  9. 什么是OOM?常见有哪些OOM?
  10. 在线学编程python_我跟爸爸学编程:从Python到C++
  11. R语言︱文本挖掘——词云wordcloud2包
  12. ssim算法计算图片_OpenCV 实现图像结构相似度算法 (SSIM 算法)
  13. OpenJudge NOI题库 116题
  14. PHP基于gettexts实现多语言i18n利用PoEdit
  15. origin数据平滑_origin怎样平滑曲线 看完你就会了
  16. 二维数组随机生成地图迷宫_经验分享:三套简单的迷宫地图生成方案
  17. wifi共享大师去广告的方法
  18. 【图像分割】基于差分进化算法优化模糊熵实现多级图像阈值分割附matlab代码
  19. 进入docker容器后,按删除键是空格解决办法
  20. 华硕b560m-PLUS WIFI主板+i5 10400F平台安装Win7

热门文章

  1. SharedObject对象聊天室
  2. JAVA保存数据库前验证字符串长度
  3. 2021春哈工大计算机系统大作业
  4. 分享 | 会 Python 的人究竟怎么炒股?
  5. Qt 5.15 安装步骤
  6. 全新界面下拉整理 点心省电3.0版
  7. 开机出现 NTLDR is Missing 的解决方法
  8. 033 Rust死灵书之重构Vec
  9. [bzoj1601]灌水(洛谷P1550)
  10. 红队笔记之权限维持技术要点总结