关于c#:Zlib兼容的压缩流?

关于c#:Zlib兼容的压缩流?

Zlib-compatible compression streams?

System.IO.Compression.GZipStream或System.IO.Compression.Deflate是否与zlib压缩兼容?


我遇到了有关Git对象的问题。在这种特定情况下,它们将对象存储为带有Zlib标头的缩小的Blob,这在RFC 1950中有说明。您可以通过创建一个包含以下内容的文件来创建兼容的Blob:

  • 两个标头字节(来自RFC 1950的CMF和FLG)的值0x78 0x01

    • CM = 8 =放气
    • CINFO = 7 = 32Kb窗口
    • FCHECK = 1 =此标头的校验和位
  • C#DeflateStream的输出
  • 输入数据为DeflateStream,大端格式的Adler32校验和(MSB优先)

我做了自己的Adler实施

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class Adler32Computer
{
    private int a = 1;
    private int b = 0;

    public int Checksum
    {
        get
        {
            return ((b * 65536) + a);
        }
    }

    private static readonly int Modulus = 65521;

    public void Update(byte[] data, int offset, int length)
    {
        for (int counter = 0; counter < length; ++counter)
        {
            a = (a + (data[offset + counter])) % Modulus;
            b = (b + a) % Modulus;
        }
    }
}

就是这样。


DotNetZip包括DeflateStream,ZlibStream和GZipStream,用于处理RFC 1950、1951和1952。所有方法均使用DEFLATE算法,但每个帧和报头字节均不同。

作为优点,DotNetZip中的流不会表现出在压缩情况下扩展数据大小的异常,这是针对内置流进行报告的。另外,没有内置的ZlibStream,而DotNetZip为您提供了与zlib良好的互操作性。


从MSDN上获得有关System.IO.Compression.GZipStream的信息:

This class represents the gzip data format, which uses an industry standard algorithm for lossless file compression and decompression.

从zlib常见问题解答中:

The gz* functions in zlib on the other hand use the gzip format.

因此,zlib和GZipStream应该可以互操作,但前提是您使用zlib函数来处理gzip格式。

据报道System.IO.Compression.Deflate和zlib不可互操作。

如果您需要处理zip文件(您可能不需要,但是其他人可能需要此文件),则需要使用SharpZipLib或其他第三方库。


我已经使用GZipStream压缩.NET XmlSerializer的输出,并且使用gunzip(在cygwin中),winzip和另一个GZipStream解压缩结果的效果非常好。

供参考,这是我在代码中所做的:

1
2
3
4
5
6
FileStream fs = new FileStream(filename, FileMode.Create, FileAccess.Write);
using (GZipStream gzStream = new GZipStream(fs, CompressionMode.Compress))
{
  XmlSerializer serializer = new XmlSerializer(typeof(MyDataType));
  serializer.Serialize(gzStream, myData);
}

然后,在C#中解压缩

1
2
3
4
5
6
FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read);
using (Stream input = new GZipStream(fs, CompressionMode.Decompress))
{
   XmlSerializer serializer = new XmlSerializer(typeof(MyDataType));
   myData = (MyDataType) serializer.Deserialize(input);
}

在cygwin中使用'file'实用程序表明,使用GZipStream和GNU GZip压缩的同一文件之间确实存在差异(可能是此线程中其他人提到的标头信息)。但是,这种差异在实践中似乎无关紧要。


gzip是deflate +一些页眉/页脚数据,例如校验和和长度等。因此,它们在某种方法可以使用另一种方法的流的意义上是不兼容的,但是它们采用相同的压缩算法。


他们只是使用zlib或deflate算法压缩数据,但未提供某些特定文件格式的输出。这意味着,如果您将流按原样存储到硬盘驱动器,则很可能将无法使用某些应用程序(gzip或winrar)打开它,因为流中不包含文件头(幻数等),因此您应该自己写。


从.NET Framework 4.5开始,System.IO.Compression.DeflateStream类使用zlib库。

从该类的MSDN文章中:

This class represents the Deflate algorithm, which is an industry-standard algorithm for lossless file compression and decompression. Starting with the .NET Framework 4.5, the DeflateStream class uses the zlib library. As a result, it provides a better compression algorithm and, in most cases, a smaller compressed file than it provides in earlier versions of the .NET Framework.


我同意安德烈亚斯。您可能无法在外部工具中打开文件,但是如果该工具需要流,则可以使用它。您还可以使用相同的压缩类将文件缩小。


推荐阅读