Saltar al contenido

Compresión / Descompresión string con C #

Después de de esta prolongada recopilación de datos solucionamos este dilema que tienen ciertos usuarios. Te regalamos la solución y nuestro objetivo es servirte de gran apoyo.

Solución:

El código para comprimir / descomprimir un string

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(string 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 string 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.GetString(mso.ToArray());
    


static void Main(string[] args) 
    byte[] r1 = Zip("StringStringStringStringStringStringStringStringStringStringStringStringStringString");
    string r2 = Unzip(r1);

Recuérdalo Zip devuelve un byte[], tiempo Unzip devuelve un string. Si quieres un string de Zip puede codificarlo en Base64 (por ejemplo, usando Convert.ToBase64String(r1)) (el resultado de Zip es MUY binario! No es algo que pueda imprimir en la pantalla o escribir directamente en un XML)

La versión sugerida es para .NET 2.0, para .NET 4.0 use el MemoryStream.CopyTo.

IMPORTANTE: El contenido comprimido no se puede escribir en el flujo de salida hasta que GZipStream sabe que tiene toda la entrada (es decir, para comprimirlo de manera efectiva necesita todos los datos). Debes asegurarte de que Dispose() de El GZipStream antes de inspeccionar el flujo de salida (p. ej., mso.ToArray()). Esto se hace con el using() bloque de arriba. Tenga en cuenta que el GZipStream es el bloque más interno y se accede a los contenidos fuera de él. Lo mismo ocurre con la descompresión: Dispose() de El GZipStream antes de intentar acceder a los datos.

de acuerdo con este fragmento, uso este código y está funcionando bien:

using System;
using System.IO;
using System.IO.Compression;
using System.Text;

namespace CompressString

    internal static class StringCompressor
    
        /// 
        /// Compresses the string.
        /// 
        /// The text.
        /// 
        public static string CompressString(string 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.ToBase64String(gZipBuffer);
        

        /// 
        /// Decompresses the string.
        /// 
        /// The compressed text.
        /// 
        public static string DecompressString(string compressedText)
        
            byte[] gZipBuffer = Convert.FromBase64String(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.GetString(buffer);
            
        
    

Con la llegada de .NET 4.0 (y superior) con los métodos Stream.CopyTo (), pensé en publicar un enfoque actualizado.

También creo que la siguiente versión es útil como un claro ejemplo de una clase autónoma para comprimir cadenas regulares en cadenas codificadas en Base64, y viceversa:

public static class StringCompression
{
    /// 
    /// Compresses a string and returns a deflate compressed, Base64 encoded string.
    /// 
    /// String to compress
    public static string Compress(string uncompressedString)
    
        byte[] compressedBytes;

        using (var uncompressedStream = new MemoryStream(Encoding.UTF8.GetBytes(uncompressedString)))
        
            using (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, I don't want to rely on that very odd behavior should it ever change
                using (var compressorStream = new DeflateStream(compressedStream, CompressionLevel.Fastest, true))
                
                    uncompressedStream.CopyTo(compressorStream);
                

                // call compressedStream.ToArray() after the enclosing DeflateStream has closed and flushed its buffer to compressedStream
                compressedBytes = compressedStream.ToArray();
            
        

        return Convert.ToBase64String(compressedBytes);
    

    /// 
    /// Decompresses a deflate compressed, Base64 encoded string and returns an uncompressed string.
    /// 
    /// String to decompress.
    public static string Decompress(string compressedString)
    
        byte[] decompressedBytes;

        var compressedStream = new MemoryStream(Convert.FromBase64String(compressedString));

        using (var decompressorStream = new DeflateStream(compressedStream, CompressionMode.Decompress))
        
            using (var decompressedStream = new MemoryStream())
            
                decompressorStream.CopyTo(decompressedStream);

                decompressedBytes = decompressedStream.ToArray();
            
        

        return Encoding.UTF8.GetString(decompressedBytes);
    

Aquí hay otro enfoque que utiliza la técnica de métodos de extensión para extender la clase String para agregar string compresión y descompresión. Puede colocar la clase a continuación en un proyecto existente y luego usarlo así:

var uncompressedString = "Hello World!";
var compressedString = uncompressedString.Compress();

y

var decompressedString = compressedString.Decompress();

Esto es:

public static class Extensions
{
    /// 
    /// Compresses a string and returns a deflate compressed, Base64 encoded string.
    /// 
    /// String to compress
    public static string Compress(this string uncompressedString)
    
        byte[] compressedBytes;

        using (var uncompressedStream = new MemoryStream(Encoding.UTF8.GetBytes(uncompressedString)))
        
            using (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, I don't want to rely on that very odd behavior should it ever change
                using (var compressorStream = new DeflateStream(compressedStream, CompressionLevel.Fastest, true))
                
                    uncompressedStream.CopyTo(compressorStream);
                

                // call compressedStream.ToArray() after the enclosing DeflateStream has closed and flushed its buffer to compressedStream
                compressedBytes = compressedStream.ToArray();
            
        

        return Convert.ToBase64String(compressedBytes);
    

    /// 
    /// Decompresses a deflate compressed, Base64 encoded string and returns an uncompressed string.
    /// 
    /// String to decompress.
    public static string Decompress(this string compressedString)
    
        byte[] decompressedBytes;

        var compressedStream = new MemoryStream(Convert.FromBase64String(compressedString));

        using (var decompressorStream = new DeflateStream(compressedStream, CompressionMode.Decompress))
        
            using (var decompressedStream = new MemoryStream())
            
                decompressorStream.CopyTo(decompressedStream);

                decompressedBytes = decompressedStream.ToArray();
            
        

        return Encoding.UTF8.GetString(decompressedBytes);
    

valoraciones y reseñas

Si guardas algún reparo y forma de reformar nuestro post te proponemos escribir un informe y con gusto lo leeremos.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *