2010-09-15 35 views
35

Bu sınama işleviyle ilgili bir sorun yaşıyorum, bir bellek dizesi alıyorum, sıkıştırın ve sıkıştırın. Sıkıştırma harika çalışıyor, ancak dekompresyonun işe yaramayacağını göremiyorum.GZipStream'i System.IO.MemoryStream ile nasıl kullanırım?

//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. 

Ben bigStream dışarı en azından benim kaynak akışı (outStream) okunurken, özellikle içinde verilere sahip olması gerektiğine inanıyoruz. bu bir MSFT hatası mı yoksa benim mi?

cevap

84

Kodunuzda ne olur, akışları açmaya devam etmektesiniz, ancak bunları asla kapatmazsınız.

  • Satır 2'de bir GZipStream oluşturursunuz. Bu akış, doğru zamana gelene kadar temel akışa hiçbir şey yazmaz. Bunu kapatarak söyleyebilirsin. Ancak, kapatırsanız, temel akışı (outStream) da kapatacaktır. Bu nedenle, üzerinde mStream.Position = 0 kullanamazsınız.

Sen her zaman tüm akışları kapalı olsun emin olmak için using kullanmalıdır. İşte kodunuzda çalışan bir varyasyon.

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); 
+7

+1 iyi cevap Timwi. Buna ek olarak, GZip'in sıkıştırmak için yapması gereken bazı veri tamponları vardır. Onu kapatıncaya kadar veri almanın bittiğini bilemez ve bu yüzden son birkaç baytı tükürmez ve kısmi akımın dekompresyonu başarısız olur. – MerickOWA

+0

Sanırım .NET 3.5 (Unity ile çalışıyoruz), yani .CopyTo henüz mevcut değil. Başka bir yerden bir akıştan diğerine nasıl kopyalanacağını öğrenmek için: http://stackoverflow.com/questions/230128/best-way-to-copy-between-two-stream-instances – Almo

+0

Bunun için teşekkürler. her iki yönde de doğru çıkışı elde etmek için akışları nasıl düzenleyeceğimizi bulmakta sorun yaşıyorum – MikeT

31

Bu bilinen bir sorundur: http://blogs.msdn.com/b/bclteam/archive/2006/05/10/592551.aspx

ben biraz bu yüzden bu işleri kodunuzu değişti

: VB.NET başka uygulama,

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); 
4

:

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 
Denemeye teşebbüs ediyorsanız
1
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(); 
     } 
    } 
1

MemoryStream'i kullanmak için g (ör. Başka bir işleve geçirerek) ancak "Kapalı Aktarım'a Erişilemiyor" özel durumunun alınması. o zaman size yardımcı olacak başka bir GZipStream kurucusu var.

LeaveOpen parametresine doğru bir şekilde ileterek, GZipStream öğesinin kendi kendine atıldıktan sonra akışı açık bırakmasını emredebilir, varsayılan olarak hedef akışı kapatır (beklemediğim). 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); 
} 
2

sıkıştırmak ve bir MemoryStream basıncı azaltmak için bir yoldur:

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

Bu açık sıkıştırılmış/dekompres akımı ayrılır ve oluşturduktan sonra gibi kullanılabilir.

İlgili konular