GZipStream 和 DeflateStream 不会解压缩所有字节

发布于 2024-07-09 05:02:08 字数 1452 浏览 6 评论 0原文

我需要一种在 .net 中压缩图像的方法,因此我考虑使用 .net GZipStream 类(或 DeflateStream)。 然而我发现解压并不总是成功,有时图像可以很好地解压,有时我会收到 GDI+ 错误,表明某些内容已损坏。

在调查这个问题后,我发现解压缩并没有返回它压缩的所有字节。 因此,如果我压缩 2257974 字节,有时只能返回 2257870 字节(实数)。

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

我尝试了压缩类 GZipStream 和 DeflateStream,并仔细检查了我的代码是否存在可能的错误。 我什至尝试将流定位为 0 并刷新所有流,但没有成功。

这是我的代码:

    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();
    }

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.

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

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.

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.

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();
    }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

把时间冻结 2024-07-16 05:02:08

添加所有要压缩的数据后,您需要Close() ZipStream; 它在内部保留了一个需要写入的未写入字节的缓冲区(即使您使用Flush())。

更一般地说,StreamIDisposable,因此您还应该使用each...(是的,我知道 MemoryStream code> 不会丢失任何数据,但如果你不养成这个习惯,它会用其他 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())
    { ... }
}

[编辑:更新评论]
不要使用MemoryStream这样的东西 - 这总是一个有趣的事情,栅栏两边都有很多票:但最终......

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

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

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.

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

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

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

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.

烟火散人牵绊 2024-07-16 05:02:08

另外 - 请记住 System.IO.Compression 中的 DeflateStream 并未实现最有效的 deflate 算法。 如果您愿意,还有 BCL GZipStream 和 DeflateStream 的替代方案; 它是在基于 zlib 代码的完全托管库中实现的,在这方面比内置的 {Deflate,GZip}Stream 表现更好。 [但是您仍然需要 Close() 流才能获取完整的字节流。 ]

这些流类在 DotNetZlib 程序集中提供,可在 DotNetZip 发行版中获取,网址为 http://DotNetZip.codeplex.com/

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

These stream classes are shipped in the DotNetZlib assembly, available in the DotNetZip distribution at http://DotNetZip.codeplex.com/.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文