如何在ZLIB.NET中使用字典?

时间:2011-12-19 14:01:34

标签: c# .net compression zlib

我正在尝试使用ZLIB .NET库中的字典,但ZStream成员inflateSetDictionary始终返回Z_STREAM_ERROR。我已将此跟踪到Inflate.inflateSetDictionary的子调用,该调用测试是否(z.istate.mode == DICT0

有没有人知道如何在这个库中使用字典或知道任何好的例子。我的代码的简化版本如下所示......

public class Form1 : System.Windows.Forms.Form
{
    static private string sDictionary = "VALUE1,VALUE2,VALUE3";

    class GZOutputStream : ZOutputStream
    {
        public GZOutputStream(Stream in_Renamed)
            : base(in_Renamed)
        {

            byte[] dictionary = System.Text.ASCIIEncoding.ASCII.GetBytes(sDictionary);
            z.inflateSetDictionary(dictionary, dictionary.Length);
        }

        public GZOutputStream(Stream in_Renamed, int level)
            : base(in_Renamed, level)
        {

            byte[] dictionary = System.Text.ASCIIEncoding.ASCII.GetBytes(sDictionary);
            z.deflateSetDictionary(dictionary, dictionary.Length);
        }
    }


    class GZInputStream : ZInputStream
    {
        public GZInputStream(Stream in_Renamed)
            : base(in_Renamed)
        {

            byte[] dictionary = System.Text.ASCIIEncoding.ASCII.GetBytes(sDictionary);
            z.inflateSetDictionary(dictionary, dictionary.Length);
        }

        public GZInputStream(Stream in_Renamed, int level)
            : base(in_Renamed, level)
        {

            byte[] dictionary = System.Text.ASCIIEncoding.ASCII.GetBytes(sDictionary);
            z.deflateSetDictionary(dictionary, dictionary.Length);
        }
    }


    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();
    }

    private void compressFile(string inFile, string outFile)
    {
        FileStream outFileStream = new System.IO.FileStream(outFile, System.IO.FileMode.Create);
        GZOutputStream outZStream = new GZOutputStream(outFileStream, 1); // 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();
        }
    }


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

}

2 个答案:

答案 0 :(得分:1)

我设法通过字典使zlib压缩工作基于DotNetZip(nugetgithub)。

由于api调用既不需要明显的,也不需要记录,也不需要简短,因此我将包装器放在它自己的nuget包ZlibWithDictionary(nugetgithub)中。

用法很简单:

var compressed_byte_array = DeflateCompression.ZlibCompressWithDictionary(
    bytes_array_to_compress, 
    CompressionLevel.Default, 
    null /*use default window size in bits; possible values 9-15*/, 
    CompressionStrategy.Default, 
    byte_array_of_dictionary
);
var decompressed_byte_array = DeflateCompression.ZlibDecompressWithDictionary(
    compressed_byte_array,
    byte_array_of_dictionary
);

如果您希望手动使用相应的zlib apis,则可以仔细阅读the source for the DeflateCompression wrapper

答案 1 :(得分:0)

虽然我没有完成解决我的问题,但我想分享我的进展......

解压缩数据流时,必须等到inflate(..)函数返回Z_NEED_DICT,因此我将以下代码段添加到ZLIB类ZInputStream和ZOutputStream中,以检查从z.inflate返回的错误值...

            if (err == zlibConst.Z_NEED_DICT)
            {
                byte[] dictionary = System.Text.ASCIIEncoding.ASCII.GetBytes(sDictionary);
                z.inflateSetDictionary(dictionary, dictionary.Length);
                err = z.inflate(flush_Renamed_Field);
            }

另外,来自Inflate.inflate函数的以下代码部分似乎有错误...

                    case DICT4: 

                    if (z.avail_in == 0)
                        return r; r = f;

                    z.avail_in--; z.total_in++;
                     z.istate.need = ((z.next_in[z.next_in_index++] & 0xff) << 24) & unchecked((int)0xff000000L);
                    z.istate.mode = DICT3;
                    goto case DICT3;

在此代码中,z.istate.need的值设置为值0xffffffffxx000000,这是不正确的,因为顶部位应为零,例如0x00000000xx0000。

以下更改修复了此问题..

z.istate.need = ((z.next_in[z.next_in_index++] & 0xff) << 24) & 0xff000000L;