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

goo*_*ate 45 c# gzip .net-4.0 c#-4.0

我遇到了这个测试函数的问题,我在其中获取内存字符串,压缩它并解压缩它.压缩效果很好,但我似乎无法使解压缩工作.

//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.
Run Code Online (Sandbox Code Playgroud)

我相信bigStream out应该至少包含数据,特别是如果我的源流(outStream)被读取.这是一个MSFT错误还是我的?

Tim*_*mwi 97

您的代码中发生的事情是您继续打开流,但您永远不会关闭它们.

  • 在第2行中,您创建了一个GZipStream.在感觉它是正确的时间之前,此流不会向底层流写入任何内容.你可以通过关闭来告诉它.

  • 但是,如果你关闭它,它也会关闭底层的流(outStream).因此你无法使用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);
Run Code Online (Sandbox Code Playgroud)

  • +1好的答案Timwi.只是为了补充一点,GZip有一些内部缓冲数据需要做才能压缩.它无法知道它完成接收数据直到你关闭它,因此它不会吐出最后几个字节并且部分流的解压缩失败. (7认同)

Ali*_*tad 35

这是一个众所周知的问题: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);
Run Code Online (Sandbox Code Playgroud)

  • 是否应该使用 new GZipStream(outStream, CompressionMode.compress, true) 来保持流打开,以便 using 语句可以按照 @briantyler 的答案中的建议关闭它? (2认同)

bri*_*ler 6

压缩和解压到 a 和从 a 解压的方法MemoryStream是:

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;
}
Run Code Online (Sandbox Code Playgroud)

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


Nik*_*lia 5

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
Run Code Online (Sandbox Code Playgroud)