我在c#中使用zlib.net来压缩和解压缩字符串。
这是我的代码
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);
}
}
public static byte[] compressString(string source)
{
byte[] buffer = System.Text.Encoding.Default.GetBytes (source);
MemoryStream memOutput = new MemoryStream ();
GZOutputStream zipOut = new GZOutputStream(memOutput, zlibConst.Z_DEFAULT_COMPRESSION);
zipOut.Write(buffer, 0, buffer.Length);
zipOut.finish();
memOutput.Seek(0, SeekOrigin.Begin);
byte[] result = memOutput.ToArray();
return result;
}
public static byte[] deCompressString(string source)
{
byte[] buffer = System.Text.Encoding.Default.GetBytes (source);
MemoryStream memOutput = new MemoryStream ();
GZOutputStream zipOut = new GZOutputStream(memOutput);
zipOut.Write(buffer, 0, buffer.Length);
zipOut.finish();
memOutput.Seek(0, SeekOrigin.Begin);
byte[] result = memOutput.ToArray();
return result;
}
当我压缩字符串时,效果很好。但是,当我解压缩 compress 函数的结果字符串时,出现异常:
ZStreamException:膨胀:
zlib.ZOutputStream.Write (System.Byte[] b1, Int32 off, Int32 len)
那么解决办法是什么呢?
public static string DeCompressToString(byte[] buffer)
{
MemoryStream memOutput = new MemoryStream();
ZOutputStream zipOut = new ZOutputStream(memOutput);
zipOut.Write(buffer, 0, buffer.Length);
zipOut.finish();
memOutput.Seek(0, SeekOrigin.Begin);
byte[] result = memOutput.ToArray();
var str = System.Text.Encoding.Default.GetString(result);
return str;
}
5年前的问题,我知道,但对于仍在寻找的人(我也是),问题是 ZOutputStream 中的 Write 方法在第一次调用 z.inflate 后返回 zlibConst.Z_NEED_DICT ,这就是字典的时间需要提供。 因此,您需要重写 Write 方法,测试该返回并在此时提供字典...
public override void Write(System.Byte[] b1, int off, int len)
{
if (len == 0)
return;
int err;
z.next_in = b1;
z.next_in_index = off;
z.avail_in = len;
do
{
z.next_out = buf;
z.next_out_index = 0;
z.avail_out = bufsize;
if (compress)
err = z.deflate(flush_Renamed_Field);
else
err = z.inflate(flush_Renamed_Field);
if (err == zlibConst.Z_NEED_DICT)
{
int y=z.inflateSetDictionary(dict, dict.Length);
err = z.inflate(flush_Renamed_Field);
}
if (err != zlibConst.Z_OK && err != zlibConst.Z_STREAM_END)
{
throw new ZStreamException((compress ? "de" : "in") + "flating: " + z.msg);
}
ms.Write(buf, 0, bufsize - z.avail_out);
}
while (z.avail_in > 0 || z.avail_out == 0);
}
}
今天偶然发现了同样的错误消息。在生产代码中使用 zlib.net 超过 15 年之后。 对于特定的二进制文件,我可以压缩它,但是在解压缩它时,一些看似随机的文件,它无法解压缩,我们总是得到
ZStreamException: inflating:
错误。
在查看了 Glen 的上述答案后,我测试了
Write(byte[], int, int)
方法重写,发现 z.inflate
在 800 个块中的大约 700 个块之后返回 -5 (Z_BUF_ERROR)。 zlib 手册 声明如下:
如果没有进展,则inflate() 返回 [...] Z_BUF_ERROR 或 如果 Z_FINISH 时输出缓冲区没有足够的空间 用过的。请注意,Z_BUF_ERROR不是致命的,并且 inflate() 可以是 再次调用更多输入和更多输出空间以继续 减压。
与
deflate()
功能基本相同。据此,可能会出现返回 Z_BUF_ERROR 的情况,在这种情况下,(解)压缩可以继续而不是抛出异常。我们现在使用的派生类是这样的:
/// <summary>
/// ZOutputStream which fixes issues in zlib.net 1.0.4
/// </summary>
internal class MyOutputStream : zlib.ZOutputStream
{
private Stream m_outStream;
public MyOutputStream(Stream outStream) : base(outStream)
{
m_outStream = outStream;
}
public MyOutputStream(Stream outStream, int level) : base(outStream, level)
{
m_outStream = out_Renamed;
}
public override void Write(byte[] buffer, int offset, int length)
{
if (length == 0)
return;
int err;
z.next_in = buffer;
z.next_in_index = offset;
z.avail_in = length;
do
{
z.next_out = buf;
z.next_out_index = 0;
z.avail_out = bufsize;
if (compress)
err = z.deflate(flush_Renamed_Field);
else
err = z.inflate(flush_Renamed_Field);
// Z_STREAM_END -> end of stream is not an error, this is also in zlib.net 1.0.4
// Z_BUF_ERROR -> no data was available in the source stream is not an error,
// this caused an exception in zlib.net 1.0.4
// (see https://www.zlib.net/manual.html)
if (err != zlib.zlibConst.Z_OK
&& err != zlib.zlibConst.Z_STREAM_END
&& err != zlib.zlibConst.Z_BUF_ERROR)
{
throw new zlib.ZStreamException((compress ? "de" : "in") + "flating: " + z.msg);
}
m_outStream.Write(buf, 0, bufsize - z.avail_out);
}
while (z.avail_in > 0 || z.avail_out == 0);
}
}
为了比较,可以在 github 上查看 zlib.net 源代码。