C# GZipStream 和 DeflateStream 不会解压缩所有字节
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/271260/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
GZipStream And DeflateStream will not decompress all bytes
提问by Bobby Z
I was in need of a way to compress images in .net so i looked into using the .net GZipStream class (or DeflateStream). However i found that decompression was not always successful, sometimes the images would decompress fine and other times i would get a GDI+ error that something is corrupted.
我需要一种在 .net 中压缩图像的方法,所以我研究了使用 .net GZipStream 类(或 DeflateStream)。然而,我发现解压并不总是成功,有时图像可以解压得很好,有时我会收到 GDI+ 错误,表明某些东西已损坏。
After investigating the issue i found that the decompression was not giving back all the bytes it compressed. So if i compressed 2257974 bytes i would sometimes get back only 2257870 bytes (real numbers).
在调查了这个问题后,我发现解压并没有返回它压缩的所有字节。所以如果我压缩了 2257974 个字节,我有时只会得到 2257870 个字节(实数)。
The most funny thing is that sometimes it would work. So i created this little test method that compresses only 10 bytes and now i don't get back anything at all.
最有趣的是,有时它会奏效。所以我创建了这个只压缩 10 个字节的小测试方法,现在我根本没有得到任何东西。
I tried it with both compression classes GZipStream and DeflateStream and i double checked my code for possible errors. I even tried positioning the stream to 0 and flushing all the streams but with no luck.
我用 GZipStream 和 DeflateStream 两个压缩类都尝试过,我仔细检查了我的代码是否有可能的错误。我什至尝试将流定位到 0 并刷新所有流,但没有运气。
Here is my code:
这是我的代码:
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();
}
采纳答案by Marc Gravell
You need to Close()the ZipStreamafter adding all the data you want to compress; it retains a buffer of unwritten bytes internally (even if you Flush()) that needs to be written.
您需要Close()在ZipStream将所有要压缩后的数据; 它在内部(即使您Flush())保留了一个需要写入的未写入字节缓冲区。
More generally, Streamis IDisposable, so you should also be usingeach... (yes, I know that MemoryStreamisn't going to lose any data, but if you don't get into this habit, it will bite you with other Streams).
更一般地说,Stream是IDisposable,所以你也应该是using每个......(是的,我知道这MemoryStream不会丢失任何数据,但如果你不养成这个习惯,它会咬你与其他人Stream)。
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())
{ ... }
}
[edit : updated re comment]
Re not usingthings like MemoryStream- this is always a fun one, with lots of votes on either side of the fence: but ultimatey...
[编辑:更新评论]不是using这样的MemoryStream- 这总是一个有趣的事情,围栏两边都有很多选票:但最终......
(rhetorical - we all know the answer...) How is MemoryStreamimplemented? is it a byte[] (owned by .NET)? is it a memory-mapped file (owned by the OS)?
(修辞——我们都知道答案......) 是如何MemoryStream实施的?它是一个字节 [](由 .NET 拥有)吗?它是内存映射文件(由操作系统拥有)吗?
The reason you aren't usingit is because you are letting knowledge of internal implementation details change how you code against a public API - i.e. you just broke the laws of encapsulation. The public API says: I am IDisposable; you "own" me; therefore, it is your job to Dispose()me when you are through.
你不是的原因using是因为你让内部实现细节的知识改变了你如何针对公共 API 进行编码 - 即你刚刚违反了封装法则。公共 API 说:我是IDisposable;你欠我的; 因此,Dispose()当您完成任务时,这是您的工作。
回答by Cheeso
Also - keep in mind the DeflateStream in System.IO.Compression does not implement the most efficient deflate algorithm. If you like, there is an alternative to the BCL GZipStream and DeflateStream; it is implemented in a fully-managed library based on zlib code, that performs better than the built-in {Deflate,GZip}Stream in this respect. [ But you still need to Close() the stream to get the full bytestream. ]
另外 - 请记住 System.IO.Compression 中的 DeflateStream 没有实现最有效的 deflate 算法。如果您愿意,可以使用 BCL GZipStream 和 DeflateStream 的替代方案;它是在基于 zlib 代码的完全托管库中实现的,在这方面比内置的 {Deflate,GZip}Stream 性能更好。[ 但是您仍然需要 Close() 流以获取完整的字节流。]
These stream classes are shipped in the DotNetZlib assembly, available in the DotNetZip distribution at http://DotNetZip.codeplex.com/.
这些流类随附在DotNetZlib组件,可在该DotNetZip分布http://DotNetZip.codeplex.com/。

