如何使用zlib.NET压缩文件?

6

我正在使用zlib.NET库来尝试解压由zlib(可能在Linux系统上)压缩的文件。以下是我的操作步骤:

zlib.ZInputStream zinput =
    new zlib.ZInputStream(File.Open(path, FileMode.Open, FileAccess.Read));

while (stopByte != (data = zinput.ReadByte()))
{
  // check data here
}

zinput.Close();

数据字节与压缩数据字节匹配,所以我一定做错了什么。

1
为了处理gzip/zlib/deflate压缩文件,即使压缩数据在文件中间开始,我发现offzip工具在reverseengineering.se上提到非常有用。它可以找到并提取压缩流,无论它们在文件中的位置如何。通过正确的命令行参数,它可以在没有标记头的纯deflate流中工作。 - CodesInChaos
6个回答

8

我跳过了zlib头(前两个字节,78 9C),然后使用内置于.net的DeflateStream,这对我有用。

using(var input = File.OpenRead(...))
using(var output = File.Create(...))
{
    // if there are additional headers before the zlib header, you can skip them:
    // input.Seek(xxx, SeekOrigin.Current);

    if (input.ReadByte() != 0x78 || input.ReadByte() != 0x9C)//zlib header
        throw new Exception("Incorrect zlib header");

    using (var deflateStream = new DeflateStream(decryptedData, CompressionMode.Decompress, true))
    {
        deflateStream.CopyTo(output);
    }
}

这个zlib deflate文件头的症状:文件以小写字母x开头,或者如果您在base64中,则以eJ开头。 - FremyCompany
2
请注意,第二个字节是压缩标志位如此处所述0x01 - 无压缩/低压缩,0x9C - 默认压缩,0xDA - 最佳压缩。 - Sven

7
除了在面对异常时未使用“using”语句关闭流之外,我认为这看起来还不错。数据一定是压缩的吗?你能在Linux上使用zlib解压它吗?
看过源代码后,我感到很可怕——例如,调用int Read(buffer, offset, length)将最终调用其内部的int Read()方法length次。鉴于这种摇摆不定的开端,我不确定我会特别信任这段代码,但我至少期望它能够稍微工作一下!你尝试使用SharpZipLib了吗?

1
我认为SharpZipLib不支持zlib,但是DotNetZip支持:http://dotnetzip.codeplex.com/ - user87453

7

看起来我犯了一个错误,假设所有虚方法都被覆盖,但事实并非如此。我正在使用zlib.ZInputStream.ReadByte(),它只是继承的Stream.ReadByte(),不执行任何膨胀操作。

我改用zlib.ZInputStream.Read(),这样就可以正常工作了。


3
这听起来像是对Stream的不良实现,因为基础的ReadByte()会调用Read()以读取确切的一个字节。 - Dave Van den Eynde
1
是的 - 实际上,它也没有覆盖Read,而是实现了read。 它还覆盖了BinaryReader,而不是Stream,这很荒谬。 我已经转而使用DotNetZip库的Ionic.Zlib命名空间,它具有适当的基于Stream的实现。 zlib.NET并不适合生产使用,实际上只是一个付费产品的预告而已。 - Ben Collins
2
刚遇到了同样的问题。我对zlib.NET并不是很印象深刻!为什么ZInputStream没有覆盖Stream呢?相反,它覆盖了BinaryReader,而且还不完整!我不喜欢这里所有解决方案似乎都建议将压缩流复制到内存中。我会尝试你建议的Ionic.ZLib。谢谢。 - Drew Noakes

2
以下代码可以帮助你们。实例化对象并利用函数。
public class FileCompressionUtility
{
    public FileCompressionUtility()
    {
    }

    public static void CopyStream(System.IO.Stream input, System.IO.Stream output)
    {
        byte[] buffer = new byte[2000];
        int len;
        while ((len = input.Read(buffer, 0, 2000)) > 0)
        {
            output.Write(buffer, 0, len);
        }
        output.Flush();
    }

    public void compressFile(string inFile, string outFile)
    {
        System.IO.FileStream outFileStream = new System.IO.FileStream(outFile, System.IO.FileMode.Create);
        zlib.ZOutputStream outZStream = new zlib.ZOutputStream(outFileStream, zlib.zlibConst.Z_DEFAULT_COMPRESSION);
        System.IO.FileStream inFileStream = new System.IO.FileStream(inFile, System.IO.FileMode.Open);
        try
        {
            CopyStream(inFileStream, outZStream);
        }
        finally
        {
            outZStream.Close();
            outFileStream.Close();
            inFileStream.Close();
        }
    }

    public void uncompressFile(string inFile, string outFile)
    {
        int data = 0;
        int stopByte = -1;
        System.IO.FileStream outFileStream = new System.IO.FileStream(outFile, System.IO.FileMode.Create);
        zlib.ZInputStream inZStream = new zlib.ZInputStream(System.IO.File.Open(inFile, System.IO.FileMode.Open, System.IO.FileAccess.Read));
        while (stopByte != (data = inZStream.Read()))
        {
            byte _dataByte = (byte)data;
            outFileStream.WriteByte(_dataByte);
        }

        inZStream.Close();
        outFileStream.Close();
    }
}

2

最近我不幸地需要将之前使用PHP进行zlib压缩的文档提供给各种浏览器和平台,包括IE7。一旦我发现这些文件是使用zlib而不是gzip进行压缩的(当时误认为是gzip),我在.NET Framework v4中以以下方式使用SharpZipLib(利用Stream.CopyTo):

public static byte[] DecompressZlib(Stream source)
{
    byte[] result = null;
    using (MemoryStream outStream = new MemoryStream())
    {
        using (InflaterInputStream inf = new InflaterInputStream(source))
        {
            inf.CopyTo(outStream);
        }
        result = outStream.ToArray();
    }
    return result;
}

如果有人需要使用SharpZipLib中的类,我想把它放在这里以便帮助他们。


0

仔细查看示例代码,它正在将数据从常规Filestream复制到ZOutputStream。解压缩必须通过该层进行。

private void decompressFile(string inFile, string outFile)
{
    System.IO.FileStream outFileStream = new System.IO.FileStream(outFile, System.IO.FileMode.Create);
    zlib.ZOutputStream outZStream = new zlib.ZOutputStream(outFileStream);
    System.IO.FileStream inFileStream = new System.IO.FileStream(inFile, System.IO.FileMode.Open);          
    try
    {
        CopyStream(inFileStream, outZStream);
    }
    finally
    {
        outZStream.Close();
        outFileStream.Close();
        inFileStream.Close();
    }
}

你应该能够在输入或输出时进行压缩/解压缩。ZInputStream绝对有压缩或解压缩的能力。 - Jon Skeet

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