Geonode logo
Geonode Team

Geonode Team

更新于:2026年10月7日

发布于:2026年9月2日

JSON 与 CSV:该选择哪种格式?

通常的比较认为,JSON 具有结构性,而 CSV 则较为简单。这种说法虽然正确,却忽略了真正引发问题的关键差异。 JSON 是一套带有强制性规则的规范。CSV 则是对大多数实现方式的描述,是在事实发生后才被记录下来的。 这种不对称性解释了你曾经遇到的几乎所有 CSV 问题,也应当成为你选择哪种格式的依据。

我们之所以撰写这篇文章,是因为我们是 Geonode,向数据采集者出售代理服务,因此我们经常看到许多抓取的数据集以错误的格式写入磁盘。免责声明很简单——格式选择与代理无关,我们也不会从您的这一决定中获利。 但这确实会影响您的存储费用、处理时间,以及您每周需要花费多少时间来排查为何某个包含逗号的字段导致下游导入失败。这些都是真实的成本,而且在您写入第一条记录之前,完全可以在您的掌控之中。

根本区别:一个是标准,另一个是习惯

这是首先需要理解的,因为其他一切都由此衍生而来。

JSON 已标准化。 RFC 8259 是一份互联网标准轨道文档。 它具有正式的语法和强制性要求,其明确存在的目的就是消除“与 JSON 其他规范的不一致之处”并修正“规范错误”。如果两个 JSON 解析器出现分歧,那么其中至少有一个是错误的,而规范会指出是哪一个。

CSV 则不然。 RFC 4180 属于信息性文档,且其以最直白的措辞明确指出这一点:

尽管 CSV 格式存在各种规范和实现……但目前尚无正式规范,这导致对 CSV 文件的解释存在广泛差异。 本节记录了大多数实现似乎遵循的格式。

“大多数实现似乎遵循”这一表述在该句中起到了关键作用。RFC 4180是对常见实践的描述,而非定义。如果两个 CSV 解析器出现分歧,两者都可能是正确的。

这正是 CSV 问题之所以具有其独特性的原因。这些问题与其说是错误,不如说是针对一种从未被完全定义的格式所产生的合理分歧——这也正是它们为何会在文件生成数月后,于系统集成接口处,在其他人的工具中浮出水面。

CSV 实际上保证了什么

RFC 4180 记录了常见的约定,了解这些约定非常重要,因为偏离这些约定往往就是问题所在。

各记录之间以 CRLF 分隔。最后一条记录末尾可能有换行符,也可能没有。文件中可能包含可选的标题行。字段之间以逗号分隔,每行应包含相同数量的字段,且“空格被视为字段的一部分,不应被忽略”。

引号的使用才是关键所在:

每个字段可以被双引号包围,也可以不被包围(不过某些程序,如 Microsoft Excel,根本不使用双引号)。

此外,“包含换行符(CRLF)、双引号和逗号的字段应使用双引号括起”,若字段中嵌入了双引号,则需“在该双引号前添加另一个双引号”进行转义。

请注意这些表态动词:“可能包含,也可能不包含。”“应”。 该 RFC 描述的是一种普遍趋势。而关于 Excel 的括号注释,表明该文档早在 2005 年就承认,全球使用最广泛的 CSV 工具并未遵循这一约定。

实际后果,按其对您造成影响的严重程度排序如下:

分隔符因地区而异。 将逗号用作小数分隔符的国家通常使用分号作为字段分隔符。德国同事导出的文件可能无法被基于逗号的解析器解析,而你们双方都没有做错什么。

编码未声明。 CSV 文件中没有任何内容声明其字符编码。UTF-8、Latin-1、Windows-1252 和 UTF-16 生成的文件看起来都像 CSV,但在错误的解析器中会显示为乱码。字节顺序标记出现不一致,导致简单的标题解析失败。

换行符不统一。 CRLF、LF,以及——在包含嵌入换行符的字段中——引号内的换行符。

不存在数据类型。 所有内容都被视为文本。007会被解析为7,2026-09-02在某些工具中被视为日期,在另一些工具中则被视为字符串,而开头的+会被省略。 通过电子表格对 CSV 文件进行往返处理确实会导致数据丢失。

而且 CSV 文件可能执行代码。 以 =、+、- 或 @ 开头的字段可能会被电子表格软件解释为公式。 这就是公式注入。当你将用户提供的数据写入 CSV 文件,而他人将在 Excel 中打开该文件时,这便构成一个真实的漏洞。缓解措施是在写入前,在这些字段前添加单引号,或通过其他方式将其中和。如果你的处理流程会从抓取或用户提交的内容中生成 CSV 文件,那么值得对此进行有针对性的处理。

JSON 能保证什么,以及它仍存在哪些不足

JSON 的规范更为严格,相应的保证也更强。

编码方式已明确规定。 RFC 8259 第 8.1 节指出:“在不属于封闭生态系统的系统之间交换的 JSON 文本,必须使用 UTF-8 进行编码。” 该规范还规定,实现“不得”在网络传输的 JSON 文本中“添加字节顺序标记”,但允许解析器忽略该标记。那些困扰 CSV 的所有编码猜测问题,在这里根本不存在。

存在类型。 字符串、数字、布尔值、null、对象和数组在语法中是可以区分的。"007" 和 7 是不同的值,且始终保持不同。

嵌套是原生的。 分层数据具有明确的表示形式,而非依赖于无人认同的约定。

JSON 在以下两个方面并不像人们想象的那样绝对:

重复键仅被不建议使用。 规范中写道:“对象内的名称‘应’(SHOULD)是唯一的”——是“应”(SHOULD),而非“必须”(MUST)。并且规范坦率地指出了后果:当名称不唯一时,“接收此类对象的软件的行为是不可预测的。 许多实现仅报告最后一个键值对;其他实现则会报告错误或解析失败。”

数值精度仅为指导,而非硬性规则。 规范允许实现对数值范围和精度设置限制,并指出:良好的互操作性源于不期望超过 IEEE 754 binary64 标准所提供的范围。 它直接指出了失败情况:“诸如 1E400 或 3.141592653589793238462643383279 之类的 JSON 数字可能表明存在潜在的互操作性问题。”

实际上,这是一种随软件发布而存在的隐性错误。当大型 64 位标识符被解析为 JavaScript 数字时会丢失精度,但不会抛出异常,导致两个不同的记录可能被视为相同值。标准的缓解措施是将大整数序列化为字符串——这最好在写入数据时就进行,而不是等到下游处理时才发现问题。 我们在关于 JSON.parse 的指南中详细探讨了解析器方面的相关内容。

大小与速度

这种权衡确实存在,而且其结果并不总是符合人们的预期。

对于扁平化的表格数据,CSV 的体积更小,通常差距很大,因为字段名只出现在表头一次,而不是出现在每一条记录中。一百万行、每个记录包含五个字段的数据,在 CSV 中只需存储五个字段名,而在 JSON 中则需要存储五百万个字段名。

压缩能大幅缩小这种差距。 重复的键在压缩时效果极佳。 经过 gzip 压缩后,JSON 在处理统一记录时的性能开销通常会降至可接受的水平——有时甚至为零。如果你正在存储压缩数据(而你确实应该这样做),那么 CSV 在体积方面的优势远不如原始数据所显示的那样明显。

在简单情况下,CSV 的解析速度更快,而在正确处理的情况下则更慢。 一个简单的 split(',') 解析器虽然速度极快,但结果是错误的。一个能正确处理引号、嵌入换行符和转义引号的符合规范的解析器,其解析成本更接近于 JSON 解析。大多数 CSV 速度对比,实际上是在将错误的解析器与正确的解析器进行暗中比较。

JSON 的真正成本在于内存,而非 CPU。 通常,解析单个大型 JSON 文档时必须将其保存在内存中。而 CSV 可以从流中逐行处理,且内存占用恒定。对于一个 10 吉字节的文件,这种差异绝非性能上的细微差别;在特定机器上,这代表着“可行”与“不可行”之间的本质区别。

这正是下一节要解决的问题。

中间方案:JSON Lines

JSON Lines(也称为 NDJSON 或换行符分隔的 JSON)是一种每行一个 JSON 文档的格式,不包含包裹数组。这是大多数人应该采用的格式,但知晓者却相对较少。

{"id": 1, "name": "Ada", "tags": ["engineer"]}
{"id": 2, "name": "Grace", "tags": ["engineer", "admiral"]}

它能为您带来:

流式处理。 每行均可独立解析,因此处理一个 100 吉字节的文件时,内存占用保持恒定。这消除了 JSON 在实际应用中最大的缺点。

仅追加写入。 新记录追加到文件末尾。无需关闭任何包裹数组,这意味着无需重写文件,且如果进程在写入过程中终止,也不会导致输出数据损坏。

部分恢复。 即使文件被截断,仍能获取每一行完整的行数据。而截断的 JSON 数组则完全无法读取——只要缺失一个大括号,整个文档就无法解析。对于任何由长期运行的任务写入的数据,仅凭这一点就足以证明该选择的合理性。

**简单的并行处理。**按行拆分,各分片独立处理。不存在跨行状态。

**完整的 JSON 语义。**类型、嵌套和无歧义编码均得以保留。

其代价微乎其微:文件大小略大于 CSV,无法直接在电子表格中打开,且每条记录都携带其键。对于抓取的数据、日志输出、事件流以及任何增量追加的内容,这都是正确的默认选择——这也是我们向任何将集合输出写入磁盘的人推荐的做法。

超越二者:Parquet 及其相关技术

值得了解,因为对于分析型工作负载而言,“JSON 还是 CSV”这个问题有时完全是错误的。

Parquet 是一种列式二进制格式。它将每列数据连续存储,这意味着一个涉及三个列、共四十次读取的查询,只会读取这三个列。 它带有模式,由于相似值集中存储,其压缩效果远优于行式文本,并且能精确保留数据类型。

优势所在:针对大型数据集的分析查询、任何规模较大的数据的长期存储,以及任何向数据仓库输送数据的管道。与 CSV 相比,其压缩比通常可达数倍,而查询性能的差距则更为显著。

其不足之处在于:该格式不适合人类阅读,无法像 JSON Lines 那样进行追加操作,且需要依赖库而非文本编辑器。对于流式处理、人与人之间的数据交换以及小规模数据,文本格式仍然是更合适的选择。

一种常见且合理的架构:先将数据收集为 JSON Lines 格式(因其支持追加且具有容错性),然后分批转换为 Parquet 格式以供分析和归档。每种格式都应根据其特性发挥优势。

按任务类型选择

任务格式原因
Web API 响应JSON与 HTTP 工具、类型和嵌套结构原生兼容
增量写入的抓取数据JSON Lines支持追加、流式处理,且在截断后仍能保留数据
向非技术同事发送数据CSV可在 Excel 中打开,这是实际需求
配置均不适用 — YAML 或 TOML注释很重要
大型分析数据集Parquet列式读取、压缩、模式
批量数据库导入CSV大多数数据库中内置的快速加载器
事件或日志流JSON Lines每行一个事件,仅支持追加
嵌套或可变结构的记录JSON 或 JSON LinesCSV 无法表达此类结构,除非制定特殊约定
包含任何用户提供的文本的数据JSON 或 JSON Lines避免引号、分隔符和公式注入的风险

三条规则可解决大多数情况,无需使用表。

如果数据是扁平的、统一的,且要导入电子表格或批量加载器,请使用 CSV。 这些确实是 CSV 的优势,其他格式无法像它一样便捷地处理这些情况。尤其是数据库批量导入方面,CSV 具有明显的优势——大多数数据库引擎都为 CSV 提供了快速处理路径,而 JSON 则没有。

如果数据是嵌套的、结构可变的,或者包含用户输入的内容,请使用 JSON 或 JSON Lines。 将嵌套数据扁平化为 CSV 需要制定一套约定,而为此制定的每套约定都曾是 bug 的根源。此外,用户输入的文本中包含逗号、引号和换行符,而这些恰恰是 CSV 处理起来最不可靠的部分。

**如果您需要持续写入记录,请使用 JSON Lines。**不要使用 CSV,因为 CSV 缺乏类型信息,您将因此丢失这些信息。也不要使用 JSON 数组,因为无法安全地向其追加数据,且进程崩溃后会留下无法解析的文件。

大家还问

JSON 比 CSV 更好吗?

对于不同的任务,答案既有“是”,也有“否”。JSON 是一种正式标准,具有数据类型、嵌套结构以及强制要求的 UTF-8 编码。对于扁平化的表格数据,CSV 文件体积更小,更适合流式处理,并且可以在电子表格软件中直接打开。 更有力的观点是,CSV 没有正式的规范——RFC 4180 明确指出这一点——这导致其在不同工具间的处理结果难以预测。

为什么我的 CSV 文件在 Excel 中显示异常?

通常是编码或分隔符的问题。 CSV 文件不会声明其字符编码,因此 Excel 会进行猜测;而将逗号用作小数分隔符的区域设置通常期望分号作为分隔符。这两个问题都源于该格式本身从未对这两者进行过明确规定。对于 Excel 而言,导出带 BOM 的 UTF-8 文件通常能解决问题,但代价是会让其他解析器感到困惑。

什么是 JSON Lines,何时应该使用它?

每行一个 JSON 文档,不包含包裹数组。当您需要增量写入记录时(如抓取的数据、日志、事件流),请使用它。它以流式方式驻留于内存中,可安全追加数据,即使发生截断,每行完整内容仍能保留,并保持完整的 JSON 类型和嵌套结构。

CSV 比 JSON 更小吗?

对于未压缩且结构扁平、数据统一的情况,通常 CSV 体积要小得多,因为字段名只需出现一次,而非每条记录都重复。压缩后,两者之间的差距会急剧缩小,因为重复的键压缩效果非常好。如果您存储的是压缩数据,那么 CSV 在体积上的优势远不如原始数据所显示的那样明显。

CSV 能处理嵌套数据吗?

原生不支持。任何嵌套都需要你自行制定约定——例如使用点分隔的列名进行扁平化、在单元格中嵌入 JSON 字符串,或者使用多个相关文件。 这些方法虽然都可行,但都意味着如果没有你制定的特定约定,通用工具将无法读取你的 CSV 文件,而这恰恰是最初使用 CSV 的主要原因。

JSON 和 CSV 哪个解析速度更快?

在简单情况下,CSV 更快,但这种比较往往不公平——一个快速的 split(',') 并不是一个正确的 CSV 解析器,而一个能正确处理引号和嵌入换行符的解析器,其解析成本则更接近 JSON。更重要的区别在于内存:CSV 是按行流式处理的,而 JSON 文档通常需要整体加载,这一点可以通过 JSON Lines 来解决。

JSON 中允许重复键吗?

规范中规定名称“应(SHOULD)”是唯一的,而非“必须(MUST)”,因此从技术上讲是允许的。规范还警告说,当键名重复时,行为是不可预测的——有些解析器会保留最后一个,有些会报错,有些则会完全失败。请将重复键视为生成该文档的工具中的一个错误。

抓取的数据应采用哪种格式?

大多数情况下,应使用 JSON Lines。抓取的记录通常具有嵌套结构且格式多变,而 CSV 对此处理不佳;此外,数据收集通常是增量式的,而 JSON 数组对此处理不佳。 如果数据确实是扁平结构且最终用于电子表格或批量导入,则使用 CSV 即可——若从抓取的文本生成 CSV 文件,请将以 =、+、- 或 @ 开头的字段进行处理,以避免公式注入。

总结

让这个决定变得容易的思路并非“结构化与简单”的对比,而是其中一种格式有明确的规范,而另一种则只是对常见做法的描述。 RFC 8259 规定了 JSON 必须具备的功能;RFC 4180 则描述了 CSV 文件通常的行为方式,并以自己的措辞明确了这一点。

正是这种差异,导致了几乎所有 CSV 问题——未声明的编码、依赖区域设置的分隔符、不一致的引号处理、在电子表格中悄然丢失的类型,以及字段被转换为公式。这些问题都不是任何解析器的错误,而是一个从未被完全定义的格式所必然导致的结果。

对于大多数编写数据而非读取数据的人来说,JSON Lines 才是最佳解决方案,但其采用率却偏低。它保留了 JSON 的数据类型、嵌套结构和已确定的编码,同时消除了其唯一的真正弱点——它支持流式处理、安全追加,且在写入被截断时,每个完整的记录都能完好无损地保留下来。 请将 CSV 保留用于它真正最擅长的两项任务:向将在电子表格中打开文件的人提供扁平化表格,以及批量加载数据库。如果数据集规模庞大且用于分析,这两种文本格式都不是理想的最终存储形式;请将其转换为列式格式,让每种格式都发挥其特有的优势。