decompress - Compresión/Descompresión cadena con C#
gzip compress c# (5)
Con el advenimiento de .NET 4.0 (y superior) con los métodos Stream.CopyTo (), pensé que publicaría 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
{
/// <summary>
/// Compresses a string and returns a deflate compressed, Base64 encoded string.
/// </summary>
/// <param name="uncompressedString">String to compress</param>
public static string CompressString(string uncompressedString)
{
var compressedStream = new MemoryStream();
var uncompressedStream = new MemoryStream(Encoding.UTF8.GetBytes(uncompressedString));
using (var compressorStream = new DeflateStream(compressedStream, CompressionMode.Compress, true))
{
uncompressedStream.CopyTo(compressorStream);
}
return Convert.ToBase64String(compressedStream.ToArray());
}
/// <summary>
/// Decompresses a deflate compressed, Base64 encoded string and returns an uncompressed string.
/// </summary>
/// <param name="compressedString">String to decompress.</param>
public static string DecompressString(string compressedString)
{
var decompressedStream = new MemoryStream();
var compressedStream = new MemoryStream(Convert.FromBase64String(compressedString));
using (var decompressorStream = new DeflateStream(compressedStream, CompressionMode.Decompress))
{
decompressorStream.CopyTo(decompressedStream);
}
return Encoding.UTF8.GetString(decompressedStream.ToArray());
}
}
Aquí hay otro enfoque que usa la técnica de métodos de extensión para extender la clase String para agregar compresión y descompresión de cadenas. Puede soltar la clase de abajo en un proyecto existente y luego usar así:
var uncompressedString = "Hello World!";
var compressedString = uncompressedString.Compress();
y
var decompressedString = compressedString.Decompress();
Esto es:
public static class Extensions
{
/// <summary>
/// Compresses a string and returns a deflate compressed, Base64 encoded string.
/// </summary>
/// <param name="uncompressedString">String to compress</param>
public static string Compress(this string uncompressedString)
{
var compressedStream = new MemoryStream();
var uncompressedStream = new MemoryStream(Encoding.UTF8.GetBytes(uncompressedString));
using (var compressorStream = new DeflateStream(compressedStream, CompressionMode.Compress, true))
{
uncompressedStream.CopyTo(compressorStream);
}
return Convert.ToBase64String(compressedStream.ToArray());
}
/// <summary>
/// Decompresses a deflate compressed, Base64 encoded string and returns an uncompressed string.
/// </summary>
/// <param name="compressedString">String to decompress.</param>
public static string Decompress(this string compressedString)
{
var decompressedStream = new MemoryStream();
var compressedStream = new MemoryStream(Convert.FromBase64String(compressedString));
using (var decompressorStream = new DeflateStream(compressedStream, CompressionMode.Decompress))
{
decompressorStream.CopyTo(decompressedStream);
}
return Encoding.UTF8.GetString(decompressedStream.ToArray());
}
}
Soy novato en .net. Estoy haciendo cadenas de compresión y descompresión en C #. Hay un XML y estoy convirtiendo en cadena y después estoy haciendo compresión y descompresión. No hay ningún error de compilación en mi código, excepto cuando descomprimo mi código y devuelvo mi cadena, devolviendo solo la mitad del XML.
A continuación está mi código, por favor corrígeme donde estoy equivocado.
Código:
class Program
{
public static string Zip(string value)
{
//Transform string 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 string
byteArray = ms.ToArray();
System.Text.StringBuilder sB = new System.Text.StringBuilder(byteArray.Length);
foreach (byte item in byteArray)
{
sB.Append((char)item);
}
ms.Close();
sw.Dispose();
ms.Dispose();
return sB.ToString();
}
public static string UnZip(string value)
{
//Transform string 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 string
System.Text.StringBuilder sB = new System.Text.StringBuilder(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);
}
}
Mi tamaño de XML es de 63 KB.
El código para comprimir / descomprimir una cadena
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);
}
Recuerde que Zip
devuelve un byte[]
, mientras que Unzip
devuelve una string
. Si quieres una cadena de Zip
, puedes codificarla Base64 (por ejemplo, usando Convert.ToBase64String(r1)
) (¡el resultado de Zip
es MUY binario! No es algo que puedas imprimir en la pantalla o escribir directamente en un XML )
La versión sugerida es para .NET 2.0, para .NET 4.0 usa MemoryStream.CopyTo
.
IMPORTANTE: El contenido comprimido no se puede escribir en la secuencia de salida hasta que GZipStream
sepa que tiene toda la información (es decir, para comprimirla efectivamente necesita todos los datos). GZipStream
de GZipStream
Dispose()
el GZipStream
antes de inspeccionar el flujo de salida (p. Ej., mso.ToArray()
). Esto se hace con el bloque using() { }
arriba. Tenga en cuenta que GZipStream
es el bloque más interno y se accede a los contenidos fuera de él. Lo mismo GZipStream
para descomprimir: Dispose()
del GZipStream
antes de intentar acceder a los datos.
Esta es una versión actualizada para .NET 4.5 y versiones posteriores que usan async / await e IEnumerables:
public static class SerializerExtensions
{
/// <summary>
/// Writes the given object instance to a binary file.
/// <para>Object type (and all child types) must be decorated with the [Serializable] attribute.</para>
/// <para>To prevent a variable from being serialized, decorate it with the [NonSerialized] attribute; cannot be applied to properties.</para>
/// </summary>
/// <typeparam name="T">The type of object being written to the XML file.</typeparam>
/// <param name="filePath">The file path to write the object instance to.</param>
/// <param name="objectToWrite">The object instance to write to the XML file.</param>
/// <param name="append">If false the file will be overwritten if it already exists. If true the contents will be appended to the file.</param>
public static byte[] Serialize<T>(this T objectToWrite)
{
using (MemoryStream stream = new MemoryStream())
{
BinaryFormatter binaryFormatter = new BinaryFormatter();
binaryFormatter.Serialize(stream, objectToWrite);
return stream.GetBuffer();
}
}
/// <summary>
/// Reads an object instance from a binary file.
/// </summary>
/// <typeparam name="T">The type of object to read from the XML.</typeparam>
/// <param name="filePath">The file path to read the object instance from.</param>
/// <returns>Returns a new instance of the object read from the binary file.</returns>
public static async Task<T> _Deserialize<T>(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<object> Deserialize(this byte[] arr)
{
object obj = await arr._Deserialize<object>();
return obj;
}
}
public static class CompressionExtensions
{
public static async Task<IEnumerable<byte>> 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<object> 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();
}
}
}
Con esto puedes serializar todo lo que admite BinaryFormatter, en lugar de solo cadenas.
Para aquellos que todavía obtienen el número mágico en el encabezado GZip no es correcto. Asegúrate de pasar en una transmisión GZip. ERROR y si su cadena fue comprimida usando php , necesitará hacer algo como:
public static string decodeDecompress(string originalReceivedSrc) {
byte[] bytes = Convert.FromBase64String(originalReceivedSrc);
using (var mem = new MemoryStream()) {
//the trick 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();
}
}
}
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
{
/// <summary>
/// Compresses the string.
/// </summary>
/// <param name="text">The text.</param>
/// <returns></returns>
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);
}
/// <summary>
/// Decompresses the string.
/// </summary>
/// <param name="compressedText">The compressed text.</param>
/// <returns></returns>
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);
}
}
}
}