GZipStream 和 DeflateStream 不会解压缩所有字节 [英] GZipStream And DeflateStream will not decompress all bytes

查看:23
本文介绍了GZipStream 和 DeflateStream 不会解压缩所有字节的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要一种在 .net 中压缩图像的方法,所以我研究了使用 .net GZipStream 类(或 DeflateStream).但是我发现解压并不总是成功,有时图像可以解压得很好,有时我会收到 GDI+ 错误,表明某些东西已损坏.

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.

在调查这个问题后,我发现解压没有返回它压缩的所有字节.所以如果我压缩了 2257974 个字节,我有时只会得到 2257870 个字节(实数).

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).

最有趣的是有时它会起作用.所以我创建了这个只压缩 10 个字节的小测试方法,现在我什么也没有得到.

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.

我用 GZipStream 和 DeflateStream 两种压缩类都尝试过,我仔细检查了我的代码是否有可能的错误.我什至尝试将流定位到 0 并刷新所有流,但没有运气.

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.

这是我的代码:

    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()).

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.

更一般地说,StreamIDisposable,所以你也应该 using 每个......(是的,我知道 MemoryStream 不会丢失任何数据,但如果你不养成这个习惯,它会被其他 Stream 咬你.

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 Streams).

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())
    { ... }
}

不要使用诸如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...

(修辞——我们都知道答案...) MemoryStream 是如何实现的?它是一个字节 [](由 .NET 拥有)吗?它是内存映射文件(由操作系统拥有)吗?

(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)?

您不使用的原因是因为您让内部实现细节的知识改变了您针对公共 API 进行编码的方式 - 即您刚刚违反了封装定律.公共 API 说:我是 IDisposable;你欠我的;因此,当你完成后,Dispose() 我是你的工作.

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.

这篇关于GZipStream 和 DeflateStream 不会解压缩所有字节的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆