将压缩的 csv 拆分为块的最有效方法

sal*_*adi 4 csv shell command-line

我有一些非常大的 gzip 压缩 csv 文件( 的压缩输出mysqldump)——每个大约 65 GB。

我需要将它们分成每个小于 4 GB(压缩后)的压缩块,记住每个 csv 文件中都存在引用的换行符。

在'nix 命令行(例如在Debian)上执行此操作的最有效方法是什么?

与此SO类似,尽管响应没有正确考虑引用的换行符。

eto*_*ght 8

一种不使用临时磁盘空间的方法。

块大小估计

起初,由于每一行的压缩率根据其内容而变化,除非您运行 2-pass 编码,否则很难获得精确的压缩后大小目标。但是,您可以通过使用来粗略估计块在压缩之前应该有多少大小

gzip -l file.csv.gz | tail -1 | awk '{print int(4*$2/$1)}'
Run Code Online (Sandbox Code Playgroud)

4此命令中的(GB) 是您压缩后每个块的目标大小,因此如果结果显示21,则意味着您可以将未压缩的文件拆分为大约21(GB)的块大小,假设该文件具有统一的熵分配。

解压、拆分和压缩

我们可以使用上面得到的chunk size来分割文件

gzip -dc file.csv.gz | split -C 21G -d - split_ --filter='gzip > $FILE.csv.gz'
Run Code Online (Sandbox Code Playgroud)
  • gzip -dc 将文件解压到标准输出
  • split -C 21G 每个输出文件最多放置 21G 记录
  • split --filter='gzip > $FILE.csv.gz' 为每个拆分的文件启用直接压缩

额外提示:替换gzip以上所有内容pigz以启用更快的多线程压缩

更新

要保留每个拆分的 gzip 文件的标头,我们可以使用

gzip -dc file.csv.gz | tail -n+2 | split - --filter='{ gzip -dc file.csv.gz | head -1; cat; } | gzip > $FILE.csv.gz'
Run Code Online (Sandbox Code Playgroud)

split为简单起见,此处忽略了 的某些选项,但您明白了。诀窍是修改过滤器选项,split以便它将原始 csv 文件中的标头添加到每个拆分文件的输出流中。

  • 我们如何在每个文件中保留标题? (2认同)