How do I use GZipStream with System.IO.MemoryStream?

前端 未结 9 916
遥遥无期
遥遥无期 2020-12-04 16:36

I am having an issue with this test function where I take an in memory string, compress it, and decompress it. The compression works great, but I can\'t seem to get the dec

相关标签:
9条回答
  • 2020-12-04 17:00

    What happens in your code is that you keep opening streams, but you never close them.

    • In line 2, you create a GZipStream. This stream will not write anything to the underlying stream until it feels it’s the right time. You can tell it to by closing it.

    • However, if you close it, it will close the underlying stream (outStream) too. Therefore you can’t use mStream.Position = 0 on it.

    You should always use using to ensure that all your streams get closed. Here is a variation on your code that works.

    var inputString = "“ ... ”";
    byte[] compressed;
    string output;
    
    using (var outStream = new MemoryStream())
    {
        using (var tinyStream = new GZipStream(outStream, CompressionMode.Compress))
        using (var mStream = new MemoryStream(Encoding.UTF8.GetBytes(inputString)))
            mStream.CopyTo(tinyStream);
    
        compressed = outStream.ToArray();
    }
    
    // “compressed” now contains the compressed string.
    // Also, all the streams are closed and the above is a self-contained operation.
    
    using (var inStream = new MemoryStream(compressed))
    using (var bigStream = new GZipStream(inStream, CompressionMode.Decompress))
    using (var bigStreamOut = new MemoryStream())
    {
        bigStream.CopyTo(bigStreamOut);
        output = Encoding.UTF8.GetString(bigStreamOut.ToArray());
    }
    
    // “output” now contains the uncompressed string.
    Console.WriteLine(output);
    
    0 讨论(0)
  • 2020-12-04 17:01

    This is a known issue: http://blogs.msdn.com/b/bclteam/archive/2006/05/10/592551.aspx

    I have changed your code a bit so this one works:

    var mStream = new MemoryStream(new byte[100]);
    var outStream = new System.IO.MemoryStream();
    
    using (var tinyStream = new GZipStream(outStream, CompressionMode.Compress))
    {
        mStream.CopyTo(tinyStream);           
    }
    
    byte[] bb = outStream.ToArray();
    
    //Decompress                
    var bigStream = new GZipStream(new MemoryStream(bb), CompressionMode.Decompress);
    var bigStreamOut = new System.IO.MemoryStream();
    bigStream.CopyTo(bigStreamOut);
    
    0 讨论(0)
  • 2020-12-04 17:06

    Please refer to below link, It is avoid to use double MemoryStream. https://stackoverflow.com/a/53644256/1979406

    0 讨论(0)
  • 2020-12-04 17:06

    I had an issue where *.CopyTo(stream)* would end up with a byte[0] result. The solution was to add .Position=0 before calling .CopyTo(stream) Answered here

    I also use a BinaryFormatter that would throw an 'End of stream encountered before parsing was completed' exception if position was not set to 0 before deserialization. Answered here

    This is the code that worked for me.

     public static byte[] SerializeAndCompressStateInformation(this IPluginWithStateInfo plugin, Dictionary<string, object> stateInfo)
        {
            byte[] retArr = new byte[] { byte.MinValue };
            try
            {
                using (MemoryStream msCompressed = new MemoryStream())//what gzip writes to
                {
                    using (GZipStream gZipStream = new GZipStream(msCompressed, CompressionMode.Compress))//setting up gzip
                    using (MemoryStream msToCompress = new MemoryStream())//what the settings will serialize to
                    {
                        BinaryFormatter formatter = new BinaryFormatter();
                        //serialize the info into bytes
                        formatter.Serialize(msToCompress, stateInfo);
                        //reset to 0 to read from beginning byte[0] fix.
                        msToCompress.Position = 0;
                        //this then does the compression
                        msToCompress.CopyTo(gZipStream);
                    }
                    //the compressed data as an array of bytes
                    retArr = msCompressed.ToArray();
                }
            }
            catch (Exception ex)
            {
                Logger.Error(ex.Message, ex);
                throw ex;
            }
            return retArr;
        }
    
    
        public static Dictionary<string, object> DeserializeAndDecompressStateInformation(this IPluginWithStateInfo plugin, byte[] stateInfo)
        {
            Dictionary<string, object> settings = new Dictionary<string, object>();
            try
            {
    
                using (MemoryStream msDecompressed = new MemoryStream()) //the stream that will hold the decompressed data
                {
                    using (MemoryStream msCompressed = new MemoryStream(stateInfo))//the compressed data
                    using (GZipStream gzDecomp = new GZipStream(msCompressed, CompressionMode.Decompress))//the gzip that will decompress
                    {
                        msCompressed.Position = 0;//fix for byte[0]
                        gzDecomp.CopyTo(msDecompressed);//decompress the data
                    }
                    BinaryFormatter formatter = new BinaryFormatter();
                    //prevents 'End of stream encountered' error
                    msDecompressed.Position = 0;
                    //change the decompressed data to the object
                    settings = formatter.Deserialize(msDecompressed) as Dictionary<string, object>;
                }
            }
            catch (Exception ex)
            {
                Logger.Error(ex.Message, ex);
                throw ex;
            }
            return settings;
        }
    
    0 讨论(0)
  • 2020-12-04 17:08

    Another implementation, in VB.NET:

    Imports System.Runtime.CompilerServices
    Imports System.IO
    Imports System.IO.Compression
    
    Public Module Compressor
    
        <Extension()> _
        Function CompressASCII(str As String) As Byte()
    
            Dim bytes As Byte() = Encoding.ASCII.GetBytes(str)
    
            Using ms As New MemoryStream
    
                Using gzStream As New GZipStream(ms, CompressionMode.Compress)
    
                    gzStream.Write(bytes, 0, bytes.Length)
    
                End Using
    
                Return ms.ToArray
    
            End Using
    
        End Function
    
        <Extension()> _
        Function DecompressASCII(compressedString As Byte()) As String
    
            Using ms As New MemoryStream(compressedString)
    
                Using gzStream As New GZipStream(ms, CompressionMode.Decompress)
    
                    Using sr As New StreamReader(gzStream, Encoding.ASCII)
    
                        Return sr.ReadToEnd
    
                    End Using
    
                End Using
    
            End Using
    
        End Function
    
        Sub TestCompression()
    
            Dim input As String = "fh3o047gh"
    
            Dim compressed As Byte() = input.CompressASCII()
    
            Dim decompressed As String = compressed.DecompressASCII()
    
            If input <> decompressed Then
                Throw New ApplicationException("failure!")
            End If
    
        End Sub
    
    End Module
    
    0 讨论(0)
  • 2020-12-04 17:12

    The way to compress and decompress to and from a MemoryStream is:

    public static Stream Compress(
        Stream decompressed, 
        CompressionLevel compressionLevel = CompressionLevel.Fastest)
    {
        var compressed = new MemoryStream();
        using (var zip = new GZipStream(compressed, compressionLevel, true))
        {
            decompressed.CopyTo(zip);
        }
    
        compressed.Seek(0, SeekOrigin.Begin);
        return compressed;
    }
    
    public static Stream Decompress(Stream compressed)
    {
        var decompressed = new MemoryStream();
        using (var zip = new GZipStream(compressed, CompressionMode.Decompress, true))
        {
            zip.CopyTo(decompressed);
        }
    
        decompressed.Seek(0, SeekOrigin.Begin);
        return decompressed;
    }
    

    This leaves the compressed / decompressed stream open and as such usable after creating it.

    0 讨论(0)
提交回复
热议问题