簡體   English   中英

如何將 GZipStream 與 System.IO.MemoryStream 一起使用?

[英]How do I use GZipStream with 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 錯誤還是我的錯誤?

在您的代碼中發生的情況是您不斷打開流,但從不關閉它們。

  • 在第 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);

這是一個已知問題: 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);

壓縮和解壓縮到MemoryStream和從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;
}

這使壓縮/解壓縮的流保持打開狀態,並在創建后可用。

另一個實現,在 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
    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();
        }
    }

如果您嘗試使用 MemoryStream(例如將其傳遞給另一個函數)但收到異常“無法訪問關閉的流”。 那么您可以使用另一個 GZipStream 構造函數來幫助您。

通過將 true 傳遞給 leaveOpen 參數,您可以指示 GZipStream 在處理自身后讓流保持打開狀態,默認情況下它會關閉目標流(這是我沒想到的)。 https://msdn.microsoft.com/en-us/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);
}

如果您仍然需要它,您可以使用帶有布爾參數的 GZipStream 構造函數(有兩個這樣的構造函數)並在那里傳遞真值:

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

在這種情況下,當您關閉 tynyStream 時,您的輸出流仍將打開。 不要忘記復制數據:

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

with zipped data現在您已經獲得了帶有壓縮數據的內存流

臭蟲和親吻你

祝你好運

請參考以下鏈接,避免使用雙 MemoryStream https://stackoverflow.com/a/53644256/1979406

我有一個問題, *.CopyTo(stream)*最終會得到一個byte[0]結果。 解決方案是在調用.CopyTo(stream)之前添加.Position=0 Answered here

我還使用了一個BinaryFormatter ,如果在反序列化之前沒有將位置設置為 0,它會拋出一個“在解析完成之前遇到的流結束”異常。 在這里回答

這是對我有用的代碼。

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM