一封写给 CSV 格式的情书

或者说,为什么那些声称 CSV 已死的人是错的

每个月左右,都会有一篇新的博客文章宣称 CSV 即将消亡,转而支持一些“明显更优越”的格式(例如 parquet、换行符分隔的 JSON、MessagePack 记录等),出现在读者的眼中。遗憾的是,这些文章通常提供非常狭隘和有偏见的比较,并且常常无法理解是什么使得 CSV 成为数据序列化中看似无法被替代的主流格式。

因此,我打算通过这篇文章,写一封情书给这种数据格式。它经常因为不正确的原因受到批评,尤其是在某种程度上“仇恨”它被认为是“酷”的时候。我的观点绝不是说 CSV 是万能的,而是为了阐明这种格式一些有时被忽视的优点。

1. CSV 非常简单

CSV 的规范就在它的标题中:“逗号分隔的值”。好吧,这有点谎言,但即便如此,该规范的内容都可以用一条推文来概括,并且可以在几秒钟内向任何人解释:逗号分隔值,换行符分隔行。现在引用包含逗号和换行符的值,双倍你的引号,就是这样。这太简单了,你甚至可能在学习编程时,在不知道它已经存在的情况下自己发明出来。

当然,这并不意味着你不应该使用专门的 CSV 解析器/写入器,因为你_会_把事情搞砸的。

2. CSV 是一种集体智慧的结晶

没有人拥有 CSV。它没有真正的规范(是的,我知道有争议的事后 RFC 4180),只是一套每个人都默认同意遵守的规则。它现在是,而且将永远是一个开放和自由的集体智慧的结晶。

3. CSV 是文本

就像 JSON、YAML 或 XML 一样,CSV 只是纯文本,你可以自由地以任何你喜欢的方式进行编码。CSV 不是二进制格式,可以用任何文本编辑器打开,并且不需要任何专门的程序来读取。这意味着,扩展开来,它可以直接被人类读取和编辑。

4. CSV 是可流式的

CSV 可以很容易地逐行读取,而不需要比容纳单行所需更多的内存。这也意味着,任何人都能够编写的一个简单的程序,可以用仅几 KB 的 RAM 读取几 GB 的 CSV 数据。

相比之下,像 parquet 这样的面向列的数据格式无法逐行流式传输文件,而不需要你在文件中跳来跳去,或者巧妙地缓冲内存,这样你就不会降低读取性能。

当然,如果你只对特定的列感兴趣,那么 CSV 就会很糟糕,因为你确实需要读取整行才能访问你感兴趣的部分。

面向列的数据格式当然非常适合 R、pandas 等的数据帧思维模式。但是,来自这套实践的 CSV 批评者往往只关心所有内容都应该装入内存的用例。

5. CSV 可以被追加

在 CSV 文件的末尾添加新行是很简单的,而且这样做非常有效。只需以追加模式 (a+) 打开文件即可。

再次强调,面向列的数据格式不能这样做,或者至少不能以直接的方式这样做。实际上,它们可以被视为磁盘上的数据帧,就像数据帧一样,添加一列非常有效,而添加新行则不然。

6. CSV 是动态类型的

请不要逃跑。让我解释一下为什么这有时是一件好事。有时在处理数据时,你可能希望具有一定的灵活性,尤其是在跨编程语言解析序列化数据时。

例如,考虑一下 JavaScript,它无法表示 64 位整数。或者什么语言、框架和库会将什么视为 null 值(不要让我开始说 pandas 和 null 值)。CSV 允许你随意解析值,并且实际上是动态类型的。但是,这既是一种优势,如果你不小心,也可能成为一个潜在的隐患。

另请注意,但这可能很难用更高级的语言(例如 python 和 JavaScript)来实现,你不需要完全解码文本来处理 CSV 单元格值,并且为了性能原因,你可以直接处理文本的二进制表示形式。

7. CSV 是简洁的

将标题只在文件开头写一次,意味着格式的正式重复量自然非常低。考虑一下 JSON 中的对象列表,或者 XML 中的等效列表,你很快就会看到在各处重复键的成本。这并不意味着 JSON 和 XML 不会很好地压缩,但很少有格式能表现出这种程度的自然简洁性。

更重要的是,字符串通常已经被最佳地表示出来,并且格式本身的开销(这里和那里的一些逗号和引号)被保持在最低限度。当然,静态类型的数字可以用更简洁的方式表示,但你也不会节省一个数量级。

8. 反向 CSV 仍然是有效的 CSV

这一点并不经常被每个人意识到,但是一个反向的(逐字节)CSV 文件,仍然是有效的 CSV。这之所以成为可能,仅仅是因为通过将引号加倍来转义引号的天才想法,这意味着转义是一个回文。如果 CSV 使用基于反斜杠的转义方案,就像在表示字符串文字时最常见的那样,这将不起作用。

但是你为什么要关心呢?好吧,这意味着你可以非常高效和非常容易地读取 CSV 文件的最后几行。只需将文件的字节按相反的顺序提供给 CSV 解析器,然后反转产生的行及其单元格的字节,你就完成了(也许先读取标题行)。

这意味着你可以很好地使用 CSV 输出作为有效恢复中止过程的一种方式。你确实可以在恒定时间内读取和解析 CSV 文件的最后几行,因为你不需要读取整个文件,而只需要将自己定位在文件末尾以缓冲反向的字节并将其提供给解析器。

9. Excel 讨厌 CSV

这清楚地表明 CSV 一定做对了什么。

签名:xan,CSV 魔术师