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 ZipStream
after 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, Stream
is IDisposable
, so you should also be using
each... (yes, I know that MemoryStream
isn't going to lose any data, but if you don't get into this habit, it will bite you with other Stream
s).
更一般地说,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 using
things 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 MemoryStream
implemented? is it a byte[] (owned by .NET)? is it a memory-mapped file (owned by the OS)?
(修辞——我们都知道答案......) 是如何MemoryStream
实施的?它是一个字节 [](由 .NET 拥有)吗?它是内存映射文件(由操作系统拥有)吗?
The reason you aren't using
it 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/。