兼容Zlib的压缩流?
System.IO.Compression.GZipStream或者System.IO.Compression.Deflate是否与zlib压缩兼容?
解决方案
回答
他们只是使用zlib或者deflate算法压缩数据,但未提供某些特定文件格式的输出。这意味着,如果我们将流按原样存储到硬盘驱动器,则很可能将无法使用某些应用程序(gzip或者winrar)打开它,因为流中不包含文件头(幻数等),因此我们应该自己写。
回答
我同意安德烈亚斯。我们可能无法使用外部工具打开文件,但是如果该工具需要流,则可以使用它。我们还可以使用相同的压缩类将文件缩小。
回答
gzip是deflate +一些页眉/页脚数据,例如校验和和长度等。因此,它们在某种方法可以使用另一种方法的流的意义上是不兼容的,但是它们采用相同的压缩算法。
回答
从有关System.IO.Compression.GZipStream的MSDN中:
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解压缩结果的效果非常好。
供参考,这是我在代码中所做的:
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#中解压缩
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中使用"文件"实用程序显示,使用GZipStream和GNU GZip压缩的同一文件之间确实存在差异(可能是该线程中其他人提到的标头信息)。但是,这种差异在实践中似乎无关紧要。
回答
DotNetZip包括DeflateStream,ZlibStream和GZipStream,用于处理RFC 1950、1951和1952. 所有方法均使用DEFLATE算法,但每个帧和报头字节均不同。
作为一个优点,DotNetZip中的流不会表现出在压缩情况下扩展数据大小的异常,这是针对内置流进行报告的。另外,没有内置的ZlibStream,而DotNetZip可以为我们提供与zlib良好的互操作性。
回答
我遇到了与Git对象有关的问题。在这种特定情况下,它们将对象存储为带有Zlib标头的缩小的Blob,这在RFC 1950中有说明。我们可以通过创建一个包含以下内容的文件来创建兼容的Blob:
- CINFO = 7 = 32Kb窗口
- FCHECK = 1 =此标头的校验和位
- C#
DeflateStream
的输出 - 将输入数据的Adler32校验和转换为Big-endian格式的" DeflateStream"(MSB在前)
我做了自己的Adler实施
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; } } }
就是这样。