【问题标题】:Compress and decompress a Stream with Compression.DeflateStream使用 Compression.DeflateStream 压缩和解压缩 Stream
【发布时间】:2012-05-22 21:32:27
【问题描述】:

我正在尝试使用Compression.DeflateStream 压缩和解压缩流。压缩似乎可以正常工作,因为下面的代码将我的 Stream 压缩为 110 字节长的数组。但是,读取解压后的 Stream 会得到一个空字符串。

class Program
{
    static void Main(string[] args)
    {
        // Compress a random string value
        string value = Path.GetRandomFileName();
        byte[] compressedBytes;

        using (var writer = new StreamWriter(new MemoryStream()))
        {
            writer.Write(value);
            writer.Flush();
            writer.BaseStream.Position = 0;

            compressedBytes = Compress(writer.BaseStream);
        }

        // Decompress compressed bytes
        Stream decompressedStream = Decompress(compressedBytes);
        // here already applies: decompressedStream.Length == 0

        using (var reader = new StreamReader(decompressedStream))
        {
            string decompressedValue = reader.ReadToEnd();

            if (value == decompressedValue)
                Console.WriteLine("Success");
            else
                Console.WriteLine("Failed");
        }
    }

    private static byte[] Compress(Stream input)
    {
        using (var compressStream = new MemoryStream())
        using (var compressor = new DeflateStream(compressStream, CompressionMode.Compress))
        {
            input.CopyTo(compressor);
            return compressStream.ToArray();
        }
    }

    private static Stream Decompress(byte[] input)
    {
        var output = new MemoryStream();

        using (var compressStream = new MemoryStream(input))
        using (var decompressor = new DeflateStream(compressStream, CompressionMode.Decompress))
            decompressor.CopyTo(output);

        output.Position = 0;
        return output;
    }
}

谁能帮我解决这个问题? 非常感谢。

【问题讨论】:

    标签: c# .net stream compression


    【解决方案1】:

    修复你的 Compress 函数:

    private static byte[] Compress(Stream input)
    {
        using(var compressStream = new MemoryStream())
        using(var compressor = new DeflateStream(compressStream, CompressionMode.Compress))
        {
            input.CopyTo(compressor);
            compressor.Close();
            return compressStream.ToArray();
        }
    }
    

    在返回结果字节数组之前未刷新压缩流。

    【讨论】:

    • 必须指出,如果您调用Flush 而不是Close,它将不起作用。我认为 Close 在内部调用 Flush 是这样做的原因,但不是。
    • @Luke: from the documentation for DeflateStream.Flush():"这个方法的当前实现不刷新内部缓冲区。内部缓冲区在对象被释放时被刷新。" 如为什么这是设计,Stream.Flush() 旨在刷新内部缓冲,但是直到它知道你在 end 时才能最终确定 deflate 流,这只有在流是 关闭.
    • 我必须向DeflateStream 构造函数添加第三个参数才能使其正常工作。 new DeflateStream(compressStream, CompressionMode.Compress, true)bool leaveOpen 防止在压缩机关闭时关闭内存流。
    • CopyTo 在 .Net 4 之前不可用。
    • 考虑到您无论如何都在使用using,因此无需Flush()˛ 或Close()。只需将ToArray() 调用移到using 之后。一切都会自动完成。
    【解决方案2】:

    所有这些答案都与理想形式相去甚远,因为你们都忘记了“使用”处理和关闭流意味着不需要额外的 Close()。我认为理想的代码应该是这样的:

    public static class CompressionHelper
    {
        public static byte[] Compress(byte[] data)
        {
            byte[] compressArray = null;
            try
            {
                using (MemoryStream memoryStream = new MemoryStream())
                {
                    using (DeflateStream deflateStream = new DeflateStream(memoryStream, CompressionMode.Compress))
                    {
                        deflateStream.Write(data, 0, data.Length);
                    }
                    compressArray = memoryStream.ToArray();
                }
            }
            catch (Exception exception)
            {
                // do something !
            }
            return compressArray;
        }
    
        public static byte[] Decompress(byte[] data)
        {
            byte[] decompressedArray = null;
            try
            {
                using (MemoryStream decompressedStream = new MemoryStream())
                {
                    using (MemoryStream compressStream = new MemoryStream(data))
                    {
                        using (DeflateStream deflateStream = new DeflateStream(compressStream, CompressionMode.Decompress))
                        {
                            deflateStream.CopyTo(decompressedStream);
                        }
                    }
                    decompressedArray = decompressedStream.ToArray();
                }
            }
            catch (Exception exception)
            {
                // do something !
            }
    
            return decompressedArray;
        }
    }
    

    【讨论】:

    • 我相信这是最干净的答案。就我而言,我必须使用重载的构造函数,并将boolean leaveOpen 设置为True。否则,处理 DeflateStream 也会关闭底层流。
    • 我认为如果我使用新的 c# futures 会更干净。
    【解决方案3】:

    尝试关闭流:

    class Program
    {
        static void Main(string[] args)
        {
            // Compress a random string value
            string value = DateTime.Now.ToLongTimeString();
            byte[] compressedBytes;
    
            using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(value)))
            {
                compressedBytes = Compress(stream);
            }
    
    
            // Decompress compressed bytes
            using (var decompressedStream = Decompress(compressedBytes))
            using (var reader = new StreamReader(decompressedStream))
            {
                string decompressedValue = reader.ReadToEnd();
    
                if (value == decompressedValue)
                    Console.WriteLine("Success");
                else
                    Console.WriteLine("Failed");
            }
        }
    
        public static byte[] Compress(Stream input)
        {
            using (var compressedStream = new MemoryStream())
            using (var zipStream = new GZipStream(compressedStream, CompressionMode.Compress))
            {
                input.CopyTo(zipStream);
                zipStream.Close();
                return compressedStream.ToArray();
            }
        }
    
        public static Stream Decompress(byte[] data)
        {
            var output = new MemoryStream();
            using(var compressedStream = new MemoryStream(data))
            using(var zipStream = new GZipStream(compressedStream, CompressionMode.Decompress))
            {
                zipStream.CopyTo(output);
                zipStream.Close();
                output.Position = 0;
                return output;
            }
        }
    }
    

    【讨论】:

    • 我正在使用相同的压缩解压缩功能。解压缩工作正常,但返回的 Stream 对象给了我。无法访问已关闭的 Stream。我正在尝试处理它时的消息。在压缩解压缩功能之前,相同的代码正在工作。有什么想法吗?
    猜你喜欢
    • 2019-01-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多