C#快速/高效地压缩大量数据块

时间:2011-11-19 04:44:38

标签: c# compression block

我有大约270k个数据块对,每对包含一个32KiB和一个16KiB块。

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

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

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

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

是否有适合该任务的压缩算法(最好是在C#中)的实现?

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

长文短篇小说: Type1主要由1组成。 Type2主要由零和1组成 Type3主要由零组成 大于128的值(尚未)。

16KiB块几乎总是由零组成

3 个答案:

答案 0 :(得分:5)

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

随机评论:“......很多速度损失可能......”不是解决性能问题的方法。测量并查看它是否确实存在。

答案 1 :(得分:4)

Gzip被称为“精细”,这意味着压缩率可以,速度很快。 如果您想要更多压缩,则存在其他替代方案,例如7z。

如果您想要更快的速度,这似乎是您的目标,更快的替代方案将以一些压缩效率为代价提供显着的速度优势。 “重要”应翻译成快许多倍,例如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%

希望这有帮助。

答案 2 :(得分:2)

你无法随意访问Deflate流,无论你多努力(除非你放弃了LZ77部分,但这就是你现在压缩比如此之高的主要原因 - 即便如此,那也是要克服的棘手问题)。这是因为压缩数据的一部分被允许引用前一部分,最多返回32K字节,这也可能依次引用另一部分,等等,你最终必须从头开始解码流以获得您想要的数据,即使您确切知道它在压缩流中的位置(目前,您不知道)。

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