使用System.IO.Compression.Gzip压缩和解压非常大的文件

3

以下是我的问题描述:

  • 我希望我的程序能够压缩和解压选定的文件
  • 我的文件非常大(20 GB+)。可以假设这些文件永远不可能适合内存
  • 即使压缩后,压缩文件仍然可能无法适应内存
  • 我想使用来自.NET Framework的System.IO.Compression.GzipStream
  • 我希望我的应用程序是并行的

作为一个新手,对于压缩/解压缩,我有以下想法:

我可以将文件分成块,并单独压缩每个块。然后将它们合并成一个整体压缩文件。 Picture showing my idea

关于这种方法的问题1 - 压缩多个块,然后将它们合并在一起是否会给我正确的结果,即如果我要反转该过程(从压缩文件开始,返回到解压缩),是否会收到相同的原始输入?

关于这种方法的问题2 - 这种方法对你来说有意义吗?也许你可以指引我一些关于这个主题的好的讲座?不幸的是,我自己找不到任何资料。

2
为什么不直接将数据从文件流通过GZip流传输,然后再通过另一个文件流输出?两个文件都无需放入内存中。 - glenebob
@glenebob和Cory,感谢你们先生,我明白了!我的理解是,我可以有多个流压缩同一个文件,每个流从不同的点开始?我接收N个流,然后将它们合并在一起? - Radoslaw Jurewicz
这个方案可能可行,但结果不会是一个有效的GZip文件。你需要发明一种文件格式。每个“块”本身都是一个有效的GZip文件。你的格式需要描述每个块,以便后续对各个块进行解压缩。 - glenebob
2
@gzip压缩可以被并行化,但我认为这不是问题所在。它似乎只是关于控制内存使用的问题。明确一下,任何有效的gzip流的连接也是一个有效的gzip流。没有需要“专有容器”的必要。 - Mark Adler
1个回答

2
您不需要分块压缩来限制内存使用。gzip被设计成流式格式,仅需要大约256KB的RAM进行压缩,而数据的大小并不重要。输入可以是1字节、20GB或100PB,压缩仍然只需要256KB的RAM。您只需读入未压缩的数据,写入压缩后的数据即可完成。
唯一需要像您所示那样分块输入的原因是为了利用多个核心进行压缩。对于您的数据量来说,这是一个非常好的理由。然后,您可以按照描述的方式处理。只要正确排序并组合输出,解压缩就可以还原原始输入。您始终可以连接有效的gzip流以生成有效的gzip流。我建议您将块大小设置得相对较大,例如兆字节,这样分块对压缩的影响不会太大。
无法以此方式分块解压缩,但解压缩速度较快,即使您能够分块解压缩,也几乎没有任何好处。解压缩通常受到i/o限制。

谢谢您的回复!我确实希望该程序能使用多个核心,这是我想要满足的关键要求之一 - 能够利用多个核心进行压缩。 - Radoslaw Jurewicz
1
@Mark Adler,您能否编辑您的回复并为第一段添加一些额外的参考资料? - Pavel Razgovorov
@PavelRazgovorov 需要额外的参考资料吗? - Mark Adler
@MarkAdler 关于gzip使用的256KB RAM,我不知道它来自哪里,只是想了解更多细节。 - Pavel Razgovorov
@PavelRazgovorov 你应该为此发布一个新问题。另外,在这里查看内存占用情况:https://zlib.net/zlib_tech.html。 - Mark Adler

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