GZipStream和DeflateStream不会解压缩所有字节
我需要在.net中压缩图像的方法,所以我查看使用.net GZipStream类(或DeflateStream)。 然而,我发现减压并不总是成功的,有时图像将解压罚款和其他时间,我会得到一个GDI +错误的东西是损坏的。
在调查了这个问题之后,我发现解压并没有给出它压缩的所有字节。 所以,如果我压缩2257974字节,我有时会回来只有2257870字节(实数)。
最有趣的是,有时它会工作。 所以我创build了这个压缩只有10个字节的小testing方法,现在我什么也没有回来。
我试了压缩类GZipStream和DeflateStream,我仔细检查了我的代码可能的错误。 我甚至尝试将stream定位到0,并冲洗所有的stream,但没有运气。
这是我的代码:
public static void TestCompression() { byte[] test = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; byte[] result = Decompress(Compress(test)); // This will fail, result.Length is 0 Debug.Assert(result.Length == test.Length); } public static byte[] Compress(byte[] data) { var compressedStream = new MemoryStream(); var zipStream = new GZipStream(compressedStream, CompressionMode.Compress); zipStream.Write(data, 0, data.Length); return compressedStream.ToArray(); } public static byte[] Decompress(byte[] data) { var compressedStream = new MemoryStream(data); var zipStream = new GZipStream(compressedStream, CompressionMode.Decompress); var resultStream = new MemoryStream(); var buffer = new byte[4096]; int read; while ((read = zipStream.Read(buffer, 0, buffer.Length)) > 0) { resultStream.Write(buffer, 0, read); } return resultStream.ToArray(); }
添加所有要压缩的数据后,需要Close()
ZipStream
; 它会在内部保留未写入字节的缓冲区(即使您需要写入Flush()
)。
更一般地说, Stream
是IDisposable
,所以你也应该using
每个…(是的,我知道MemoryStream
不会丢失任何数据,但是如果你没有进入这个习惯,它会咬你Stream
s)。
public static byte[] Compress(byte[] data) { using (var compressedStream = new MemoryStream()) using (var zipStream = new GZipStream(compressedStream, CompressionMode.Compress)) { zipStream.Write(data, 0, data.Length); zipStream.Close(); return compressedStream.ToArray(); } } public static byte[] Decompress(byte[] data) { using(var compressedStream = new MemoryStream(data)) using(var zipStream = new GZipStream(compressedStream, CompressionMode.Decompress)) using (var resultStream = new MemoryStream()) { ... } }
不要using
像MemoryStream
这样的东西 – 这总是一个有趣的,在篱笆的两边有很多票:但终极…
(修辞 – 我们都知道答案…) MemoryStream
是如何实现的? 它是一个字节[](由.NET拥有)? 它是一个内存映射文件(由操作系统拥有)?
你不using
它的原因是因为你让内部实现细节的知识改变你如何对公共API进行编码 – 也就是说你打破了封装法则。 公共API说:我是IDisposable
; 你欠我的; 因此,当你通过时, Dispose()
我是你的工作。
另外 – 请记住System.IO.Compression中的DeflateStream没有实现最有效的deflatealgorithm。 如果你喜欢的话,BCL GZipStream和DeflateStream是另一种select; 它是在一个基于zlib代码的完全托pipe的库中实现的,比在这方面内置的{Deflate,GZip} Stream更好。 [但你仍然需要closures()stream来获取完整的字节stream。 ]
这些stream类在DotNetZlib程序集中提供,位于http://DotNetZip.codeplex.com/的DotNetZip发行版中。;