c#快速/有效地压缩大量数据块

本文关键字:数据 压缩 快速 有效地 | 更新日期: 2023-09-27 18:15:05

我有大约270k数据块对,每对由一个32KiB和一个16KiB块组成。

当我将它们保存到一个文件中时,我当然会得到一个非常大的文件。但是数据很容易被压缩。
使用WinRAR压缩5.48GiB的文件后,使用强压缩,得到的文件大小为37.4MiB。

但是我需要随机访问每个单独的块,所以我只能单独压缩块。
为此,我使用了。net提供的Deflate类,它将文件大小减小到382MiB(这是我可以接受的)。但是速度不够快。

很多速度损失可能是由于总是为每个块创建新的MemoryStream和Deflate实例。但它们似乎不是为重复使用而设计的。

我猜(很多?)更好的压缩可以实现当使用一个"全局"字典,而不是每个块一个。

是否有一个压缩算法的实现(最好是在c#中),适合于该任务?

以下链接包含每个字节数出现的百分比,分为三种块类型(仅32KiB块)。第一和第三块类型的发生率为37.5%,第二块类型为25%。字体百分比

长文件短故事:类型1主要由1组成。类型2主要由0和1组成类型3主要由零组成大于128的值不存在。

16KiB块几乎总是由零组成

c#快速/有效地压缩大量数据块

如果你想尝试不同的压缩,你可以从RLE开始,它应该适合你的数据- http://en.wikipedia.org/wiki/Run-length_encoding -即使在最简单的实现中,它也会非常快。相关的http://en.wikipedia.org/wiki/Category:Lossless_compression_algorithms包含更多的链接,以开始其他算法,如果你想滚动你自己或找到别人的实现。

随机注释:"…"很多速度损失可能是……"并不是解决性能问题的方法。

Gzip是已知的"fine",这意味着压缩比还可以,速度也不错。如果需要更多的压缩,还有其他的选择,比如7z。

如果您想要更快的速度,这似乎是您的目标,那么更快的替代方案将以牺牲一些压缩效率为代价提供显著的速度优势。"Significant"要翻译成快很多倍的形式,比如5x-10x。这样的算法更适合"内存中"压缩场景,比如您的场景,因为它们使得访问压缩块几乎没有痛苦。

作为一个例子,Clayton Stangeland刚刚为c#发布了LZ4。在BSD许可下,源代码可以在这里获得:https://github.com/stangelandcl/LZ4Sharp

在项目主页上有一些与gzip的比较指标,例如:

i5 memcpy 1658 MB/s
i5 Lz4 Compression 270 MB/s Decompression 1184 MB/s  
i5 LZ4C# Compression 207 MB/s Decompression 758 MB/s 49%
i5 LZ4C# whole corpus Compression 267 MB/s Decompression 838 MB/s Ratio 47%
i5 gzip whole corpus Compression 48 MB/s Decompression 266 MB/s Ratio 33%

无论您多么努力尝试,您都不能随机访问Deflate流(除非您放弃LZ77部分,但这是现在使压缩比如此之高的主要原因—即使这样,也有棘手的问题需要规避)。这是因为压缩数据的一部分被允许引用前一部分最多32K字节,这也可能依次引用另一部分,等等,你最终不得不从头开始解码流以获得你想要的数据,即使你确切地知道它在压缩流中的位置(目前,你不知道)。

但是,你可以做的是压缩许多(但不是全部)块一起使用一个流。然后你会得到相当好的速度和压缩,但你不需要解压缩所有块来得到你想要的那个;就是你的块恰好在其中的那个块。您需要一个额外的索引来跟踪每个压缩块在文件中的起始位置,但这是相当低的开销。可以把它看作是将所有内容压缩在一起(这对压缩很好,但对随机访问很糟糕)和单独压缩每个块(这对随机访问很好,但对压缩和速度很糟糕)之间的折衷。