Chaîne de compression / décompression avec C #

Je suis débutant dans .net. Je fais des chaînes de compression et de décompression en C #. Il y a un XML et je suis en train de convertir en ssortingng et après je fais de la compression et de la décompression.

Voici mon code, corrigez-moi s’il vous plaît où je me trompe.

Code:

class Program { public static ssortingng Zip(ssortingng value) { //Transform ssortingng into byte[] byte[] byteArray = new byte[value.Length]; int indexBA = 0; foreach (char item in value.ToCharArray()) { byteArray[indexBA++] = (byte)item; } //Prepare for compress System.IO.MemoryStream ms = new System.IO.MemoryStream(); System.IO.Compression.GZipStream sw = new System.IO.Compression.GZipStream(ms, System.IO.Compression.CompressionMode.Compress); //Compress sw.Write(byteArray, 0, byteArray.Length); //Close, DO NOT FLUSH cause bytes will go missing... sw.Close(); //Transform byte[] zip data to ssortingng byteArray = ms.ToArray(); System.Text.SsortingngBuilder sB = new System.Text.SsortingngBuilder(byteArray.Length); foreach (byte item in byteArray) { sB.Append((char)item); } ms.Close(); sw.Dispose(); ms.Dispose(); return sB.ToSsortingng(); } public static ssortingng UnZip(ssortingng value) { //Transform ssortingng into byte[] byte[] byteArray = new byte[value.Length]; int indexBA = 0; foreach (char item in value.ToCharArray()) { byteArray[indexBA++] = (byte)item; } //Prepare for decompress System.IO.MemoryStream ms = new System.IO.MemoryStream(byteArray); System.IO.Compression.GZipStream sr = new System.IO.Compression.GZipStream(ms, System.IO.Compression.CompressionMode.Decompress); //Reset variable to collect uncompressed result byteArray = new byte[byteArray.Length]; //Decompress int rByte = sr.Read(byteArray, 0, byteArray.Length); //Transform byte[] unzip data to ssortingng System.Text.SsortingngBuilder sB = new System.Text.SsortingngBuilder(rByte); //Read the number of bytes GZipStream red and do not a for each bytes in //resultByteArray; for (int i = 0; i < rByte; i++) { sB.Append((char)byteArray[i]); } sr.Close(); ms.Close(); sr.Dispose(); ms.Dispose(); return sB.ToString(); } static void Main(string[] args) { XDocument doc = XDocument.Load(@"D:\RSP.xml"); string val = doc.ToString(SaveOptions.DisableFormatting); val = Zip(val); val = UnZip(val); } } 

Ma taille XML est de 63 Ko.

Le code pour compresser / décompresser une chaîne

 public static void CopyTo(Stream src, Stream dest) { byte[] bytes = new byte[4096]; int cnt; while ((cnt = src.Read(bytes, 0, bytes.Length)) != 0) { dest.Write(bytes, 0, cnt); } } public static byte[] Zip(ssortingng str) { var bytes = Encoding.UTF8.GetBytes(str); using (var msi = new MemoryStream(bytes)) using (var mso = new MemoryStream()) { using (var gs = new GZipStream(mso, CompressionMode.Compress)) { //msi.CopyTo(gs); CopyTo(msi, gs); } return mso.ToArray(); } } public static ssortingng Unzip(byte[] bytes) { using (var msi = new MemoryStream(bytes)) using (var mso = new MemoryStream()) { using (var gs = new GZipStream(msi, CompressionMode.Decompress)) { //gs.CopyTo(mso); CopyTo(gs, mso); } return Encoding.UTF8.GetSsortingng(mso.ToArray()); } } static void Main(ssortingng[] args) { byte[] r1 = Zip("SsortingngSsortingngSsortingngSsortingngSsortingngSsortingngSsortingngSsortingngSsortingngSsortingngSsortingngSsortingngSsortingngSsortingng"); ssortingng r2 = Unzip(r1); } 

Rappelez-vous que Zip renvoie un byte[] , alors que Unzip renvoie une ssortingng . Si vous voulez une chaîne de Zip Base64 peut l’encoder (par exemple en utilisant Convert.ToBase64Ssortingng(r1) ) (le résultat de Zip est TRÈS binary! Ce n’est pas quelque chose que vous pouvez imprimer à l’écran ou écrire directement dans un XML) )

La version proposée est pour .NET 2.0, pour .NET 4.0, utilisez le MemoryStream.CopyTo .

IMPORTANT: le contenu compressé ne peut pas être écrit dans le stream de sortie tant que GZipStream sait pas qu’il a toutes les entrées (c.-à-d. GZipStream doit être compressé efficacement pour toutes les données). Vous devez vous assurer que Dispose() de GZipStream avant d’inspecter le stream de sortie (par exemple, mso.ToArray() ). Ceci est fait avec le bloc using() { } ci-dessus. Notez que GZipStream est le bloc le plus interne et que le contenu est accessible en dehors de celui-ci. Il en va de même pour la décompression: Dispose() du GZipStream avant de tenter d’accéder aux données.

selon ce snippet j’utilise ce code et ça marche très bien:

 using System; using System.IO; using System.IO.Compression; using System.Text; namespace CompressSsortingng { internal static class SsortingngCompressor { ///  /// Compresses the ssortingng. ///  /// The text. ///  public static ssortingng CompressSsortingng(ssortingng text) { byte[] buffer = Encoding.UTF8.GetBytes(text); var memoryStream = new MemoryStream(); using (var gZipStream = new GZipStream(memoryStream, CompressionMode.Compress, true)) { gZipStream.Write(buffer, 0, buffer.Length); } memoryStream.Position = 0; var compressedData = new byte[memoryStream.Length]; memoryStream.Read(compressedData, 0, compressedData.Length); var gZipBuffer = new byte[compressedData.Length + 4]; Buffer.BlockCopy(compressedData, 0, gZipBuffer, 4, compressedData.Length); Buffer.BlockCopy(BitConverter.GetBytes(buffer.Length), 0, gZipBuffer, 0, 4); return Convert.ToBase64Ssortingng(gZipBuffer); } ///  /// Decompresses the ssortingng. ///  /// The compressed text. ///  public static ssortingng DecompressSsortingng(ssortingng compressedText) { byte[] gZipBuffer = Convert.FromBase64Ssortingng(compressedText); using (var memoryStream = new MemoryStream()) { int dataLength = BitConverter.ToInt32(gZipBuffer, 0); memoryStream.Write(gZipBuffer, 4, gZipBuffer.Length - 4); var buffer = new byte[dataLength]; memoryStream.Position = 0; using (var gZipStream = new GZipStream(memoryStream, CompressionMode.Decompress)) { gZipStream.Read(buffer, 0, buffer.Length); } return Encoding.UTF8.GetSsortingng(buffer); } } } } 

Avec l’avènement de .NET 4.0 (et supérieur) avec les méthodes Stream.CopyTo (), j’ai pensé que je publierais une approche mise à jour.

Je pense également que la version ci-dessous est utile comme exemple clair de classe autonome pour la compression de chaînes régulières en chaînes codées en Base64, et inversement:

 public static class SsortingngCompression { ///  /// Compresses a ssortingng and returns a deflate compressed, Base64 encoded ssortingng. ///  /// Ssortingng to compress public static ssortingng Compress(ssortingng uncompressedSsortingng) { byte[] compressedBytes; using (var uncompressedStream = new MemoryStream(Encoding.UTF8.GetBytes(uncompressedSsortingng))) { var compressedStream = new MemoryStream(); // setting the leaveOpen parameter to true to ensure that compressedStream will not be closed when compressorStream is disposed // this allows compressorStream to close and flush its buffers to compressedStream and guarantees that compressedStream.ToArray() can be called afterward // although MSDN documentation states that ToArray() can be called on a closed MemoryStream, this approach avoids relying on that very odd behavior should it ever change using (var compressorStream = new DeflateStream(compressedStream, CompressionLevel.Fastest, true)) { uncompressedStream.CopyStreamTo(compressorStream); } // call compressedStream.ToArray() after the enclosing DeflateStream has closed and flushed its buffer to compressedStream compressedBytes = compressedStream.ToArray(); } return Convert.ToBase64Ssortingng(compressedBytes); } ///  /// Decompresses a deflate compressed, Base64 encoded ssortingng and returns an uncompressed ssortingng. ///  /// Ssortingng to decompress. public static ssortingng Decompress(ssortingng compressedSsortingng) { byte[] decompressedBytes; var compressedStream = new MemoryStream(Convert.FromBase64Ssortingng(compressedSsortingng)); using (var decompressorStream = new DeflateStream(compressedStream, CompressionMode.Decompress)) { using (var decompressedStream = new MemoryStream()) { decompressorStream.CopyStreamTo(decompressedStream); decompressedBytes = decompressedStream.ToArray(); } } return Encoding.UTF8.GetSsortingng(decompressedBytes); } 

Voici une autre approche utilisant la technique des méthodes d’extension pour étendre la classe Ssortingng afin d’append la compression et la décompression de chaîne. Vous pouvez déposer la classe ci-dessous dans un projet existant, puis l’utiliser comme suit:

 var uncompressedSsortingng = "Hello World!"; var compressedSsortingng = uncompressedSsortingng.Compress(); 

et

 var decompressedSsortingng = compressedSsortingng.Decompress(); 

En être témoin:

 public static class Extensions { ///  /// Compresses a ssortingng and returns a deflate compressed, Base64 encoded ssortingng. ///  /// Ssortingng to compress public static ssortingng Compress(this ssortingng uncompressedSsortingng) { byte[] compressedBytes; using (var uncompressedStream = new MemoryStream(Encoding.UTF8.GetBytes(uncompressedSsortingng))) { var compressedStream = new MemoryStream(); // setting the leaveOpen parameter to true to ensure that compressedStream will not be closed when compressorStream is disposed // this allows compressorStream to close and flush its buffers to compressedStream and guarantees that compressedStream.ToArray() can be called afterward // although MSDN documentation states that ToArray() can be called on a closed MemoryStream, this approach avoids relying on that very odd behavior should it ever change using (var compressorStream = new DeflateStream(compressedStream, CompressionLevel.Fastest, true)) { uncompressedStream.CopyStreamTo(compressorStream); } // call compressedStream.ToArray() after the enclosing DeflateStream has closed and flushed its buffer to compressedStream compressedBytes = compressedStream.ToArray(); } return Convert.ToBase64Ssortingng(compressedBytes); } ///  /// Decompresses a deflate compressed, Base64 encoded ssortingng and returns an uncompressed ssortingng. ///  /// Ssortingng to decompress. public static ssortingng Decompress(this ssortingng compressedSsortingng) { byte[] decompressedBytes; var compressedStream = new MemoryStream(Convert.FromBase64Ssortingng(compressedSsortingng)); using (var decompressorStream = new DeflateStream(compressedStream, CompressionMode.Decompress)) { using (var decompressedStream = new MemoryStream()) { decompressorStream.CopyStreamTo(decompressedStream); decompressedBytes = decompressedStream.ToArray(); } } return Encoding.UTF8.GetSsortingng(decompressedBytes); } 

Pour ceux qui obtiennent encore le numéro magique dans l’en-tête GZip n’est pas correct. Assurez-vous de transmettre un stream GZip. ERREUR et si votre chaîne a été compressée en utilisant PHP, vous devrez faire quelque chose comme:

  public static ssortingng decodeDecompress(ssortingng originalReceivedSrc) { byte[] bytes = Convert.FromBase64Ssortingng(originalReceivedSrc); using (var mem = new MemoryStream()) { //the sortingck is here mem.Write(new byte[] { 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0, 8); mem.Write(bytes, 0, bytes.Length); mem.Position = 0; using (var gzip = new GZipStream(mem, CompressionMode.Decompress)) using (var reader = new StreamReader(gzip)) { return reader.ReadToEnd(); } } } 

Ceci est une version mise à jour pour .NET 4.5 et versions ultérieures utilisant async / wait et IEnumerables:

 public static class CompressionExtensions { public static async Task> Zip(this object obj) { byte[] bytes = obj.Serialize(); using (MemoryStream msi = new MemoryStream(bytes)) using (MemoryStream mso = new MemoryStream()) { using (var gs = new GZipStream(mso, CompressionMode.Compress)) await msi.CopyToAsync(gs); return mso.ToArray().AsEnumerable(); } } public static async Task Unzip(this byte[] bytes) { using (MemoryStream msi = new MemoryStream(bytes)) using (MemoryStream mso = new MemoryStream()) { using (var gs = new GZipStream(msi, CompressionMode.Decompress)) { //gs.CopyTo(mso); await gs.CopyToAsync(mso); } return mso.ToArray().Deserialize(); } } } public static class SerializerExtensions { ///  /// Writes the given object instance to a binary file. /// Object type (and all child types) must be decorated with the [Serializable] atsortingbute. /// To prevent a variable from being serialized, decorate it with the [NonSerialized] atsortingbute; cannot be applied to properties. ///  /// The type of object being written to the XML file. /// The file path to write the object instance to. /// The object instance to write to the XML file. /// If false the file will be overwritten if it already exists. If true the contents will be appended to the file. public static byte[] Serialize(this T objectToWrite) { using (MemoryStream stream = new MemoryStream()) { BinaryFormatter binaryFormatter = new BinaryFormatter(); binaryFormatter.Serialize(stream, objectToWrite); return stream.GetBuffer(); } } ///  /// Reads an object instance from a binary file. ///  /// The type of object to read from the XML. /// The file path to read the object instance from. /// Returns a new instance of the object read from the binary file. public static async Task _Deserialize(this byte[] arr) { using (MemoryStream stream = new MemoryStream()) { BinaryFormatter binaryFormatter = new BinaryFormatter(); await stream.WriteAsync(arr, 0, arr.Length); stream.Position = 0; return (T)binaryFormatter.Deserialize(stream); } } public static async Task Deserialize(this byte[] arr) { object obj = await arr._Deserialize(); return obj; } } 

Avec cela, vous pouvez sérialiser tout ce que BinaryFormatter supporte, au lieu des chaînes.