我如何将GZipStream与System.IO.MemoryStream一起使用?

我在使用此测试函数时遇到了一个问题,在该函数中,我输入一个内存字符串,然后对其进行压缩和解压缩。 压缩效果很好,但是我似乎无法进行解压缩。

//Compress
System.IO.MemoryStream outStream = new System.IO.MemoryStream();                
GZipStream tinyStream = new GZipStream(outStream, CompressionMode.Compress);
mStream.Position = 0;
mStream.CopyTo(tinyStream);

//Decompress    
outStream.Position = 0;
GZipStream bigStream = new GZipStream(outStream, CompressionMode.Decompress);
System.IO.MemoryStream bigStreamOut = new System.IO.MemoryStream();
bigStream.CopyTo(bigStreamOut);

//Results:
//bigStreamOut.Length == 0
//outStream.Position == the end of the stream.

我相信bigStream out至少应该包含数据,尤其是在读取我的源流(outStream)的情况下。 这是MSFT错误还是我的?

goodguys_activate asked 2020-07-20T13:39:09Z
8个解决方案
95 votes

代码中发生的事情是您不断打开流,但是从不关闭它们。

  • 在第2行中,您创建了using。在感觉到合适的时间之前,该流不会向基础流写入任何内容。 您可以通过关闭它来告诉它。

  • 但是,如果关闭它,它也会关闭基础流(using)。 因此,您不能在其上使用mStream.Position = 0

您应该始终使用using来确保关闭所有流。 这是您的代码的有效变体。

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);
Timwi answered 2020-07-20T13:39:30Z
34 votes

这是一个已知的问题:[http://blogs.msdn.com/b/bclteam/archive/2006/05/10/592551.aspx]

我对您的代码进行了一些更改,因此该代码有效:

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);
Aliostad answered 2020-07-20T13:39:55Z
5 votes

在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
Nikolai Koudelia answered 2020-07-20T13:40:14Z
2 votes

在2974847522558182182400之间进行压缩的方法是:

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

这将使压缩/解压缩的流保持打开状态,并在创建后可用。

briantyler answered 2020-07-20T13:40:39Z
1 votes
    public static byte[] compress(byte[] data)
    {
        using (MemoryStream outStream = new MemoryStream())
        {
            using (GZipStream gzipStream = new GZipStream(outStream, CompressionMode.Compress))
            using (MemoryStream srcStream = new MemoryStream(data))
                srcStream.CopyTo(gzipStream);
            return outStream.ToArray();
        }
    }

    public static byte[] decompress(byte[] compressed)
    {
        using (MemoryStream inStream = new MemoryStream(compressed))
        using (GZipStream gzipStream = new GZipStream(inStream, CompressionMode.Decompress))
        using (MemoryStream outStream = new MemoryStream())
        {
            gzipStream.CopyTo(outStream);
            return outStream.ToArray();
        }
    }
PhonPanom answered 2020-07-20T13:40:54Z
1 votes

如果您尝试使用MemoryStream(例如,将其传递给另一个函数)却收到异常“无法访问封闭的流”。 然后可以使用另一个GZipStream构造函数来为您提供帮助。

通过将true传递给LeaveOpen参数,您可以指示GZipStream丢弃自身后使流保持打开状态,默认情况下它将关闭目标流(这没想到)。 [https://msdn.microsoft.com/zh-CN/library/27ck2z1y(v=vs.110).aspx]

using (FileStream fs = File.OpenRead(f))
using (var compressed = new MemoryStream())
{
    //Instruct GZipStream to leave the stream open after performing the compression.
    using (var gzipstream = new GZipStream(compressed, CompressionLevel.Optimal, true))
        fs.CopyTo(gzipstream);

    //Do something with the memorystream
    compressed.Seek(0, SeekOrigin.Begin);
    MyFunction(compressed);
}
Snives answered 2020-07-20T13:41:19Z
0 votes

如果仍然需要,则可以使用GZipStream构造函数和boolean参数(有两个这样的构造函数)并在其中传递true值:

tinyStream = new GZipStream(outStream, CompressionMode.Compress, true);

在这种情况下,当您关闭tynyStream时,您的输出流仍将打开。 不要忘记复制数据:

mStream.CopyTo(tinyStream);
tinyStream.Close();

现在您已经有了带压缩数据的内存流

你的臭虫和吻

祝好运

Олег Рубан answered 2020-07-20T13:41:57Z
0 votes

请参考以下链接,避免使用双重MemoryStream。[https://stackoverflow.com/a/53644256/1979406]

Haryono answered 2020-07-20T13:42:17Z
translate from https://stackoverflow.com:/questions/3722192/how-do-i-use-gzipstream-with-system-io-memorystream