J'ai un problème avec cette fonction de test où je prends une chaîne en mémoire, la compresse et la décompresse. La compression fonctionne très bien, mais je ne parviens pas à faire fonctionner la décompression.
//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.
Je pense que bigStream out devrait au moins contenir des données, surtout si mon flux source (outStream) est en cours de lecture. est-ce un bug de MSFT ou le mien?
Ce qui se passe dans votre code, c'est que vous continuez à ouvrir des flux, mais vous ne les fermez jamais.
À la ligne 2, vous créez une GZipStream
. Ce flux n'écrira rien dans le flux sous-jacent tant qu'il n'aura pas l'impression que c'est le bon moment. Vous pouvez le dire en le fermant.
Toutefois, si vous le fermez, le flux sous-jacent (outStream
) sera également fermé. Par conséquent, vous ne pouvez pas utiliser mStream.Position = 0
dessus.
Vous devez toujours utiliser using
pour vous assurer que tous vos flux sont fermés. Voici une variation de votre code qui fonctionne.
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);
Il s'agit d'un problème connu: http://blogs.msdn.com/b/bclteam/archive/2006/05/10/592551.aspx
J'ai un peu changé votre code pour que celui-ci fonctionne:
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);
Une autre implémentation, dans 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
La manière de compresser et de décompresser vers et depuis une MemoryStream
est la suivante:
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;
}
Cela laisse le flux compressé/décompressé ouvert et, en tant que tel, utilisable après sa création.
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();
}
}
Si vous essayez d'utiliser MemoryStream (par exemple, en le passant dans une autre fonction) mais en recevant l'exception "Impossible d'accéder à un flux fermé". Ensuite, il existe un autre constructeur GZipStream que vous pouvez utiliser pour vous aider.
En passant un paramètre true au paramètre leaveOpen, vous pouvez indiquer à GZipStream de laisser le flux ouvert après s'être débarrassé de lui-même. Par défaut, le flux cible est fermé (ce à quoi je ne m'attendais pas). 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);
}
Si vous en avez toujours besoin, vous pouvez utiliser le constructeur GZipStream avec un argument booléen (il en existe deux) et y transmettre la valeur vraie:
tinyStream = new GZipStream(outStream, CompressionMode.Compress, true);
Dans ce cas, lorsque vous fermerez votre tynyStream, votre flux sortant sera toujours ouvert. N'oubliez pas de copier les données:
mStream.CopyTo(tinyStream);
tinyStream.Close();
Maintenant, vous avez un flux de mémoire outStream avec des données zippées
Bugs et bisous pour U
Bonne chance
S'il vous plaît se référer au lien ci-dessous, Il est éviter d'utiliser double MemoryStream . https://stackoverflow.com/a/53644256/1979406