Blog dedicado a la programación .NET y la informática en general

Tengo un programa para hacer las publicaciones de mis proyectos, este tiene la opción de hacer una copia de seguridad de los ficheros modificados, pero no los comprime.

Hoy voy a explicar cómo usar en .NET el que para mí es el mejor compresor de ficheros, 7zip, el cual además de tener mejor resultados en compresión también es el más rápido.

Introducción a la compresión en .NET

Inicialmente desde la versión 2.0 de Framework, Microsoft nos ofrecía en la librería System.IO.Compression las clases para comprimir DeflateStream y GZipStream.

Las diferencia fundamental entre estas clases radica en que GZipStream originalmente usa el algoritmo de DeflateStream pero se puede extender para que utilice otros formatos de compresión.

Hay un montón de ejemplos en internet, el problema fundamental es a la hora de comprimir una carpeta entera, así que os dejo el ejemplo más completo que he encontrado aquí.

La mayoría de la gente usa otras librerías de terceros como DotNetZip o también SharpZipLib, que son mucho más fácil de manejar y de la que hay también mucha información en Internet.

Pero como bien he dicho al principio de este artículo yo me quedo con el algoritmo LMZA que usa 7zip.

Paquete de Desarrollo de Software LMZA

El creador de 7zi,p Igor Pavlov, muy amablemente nos ha dejado un SDK de LMZA donde tiene un ejemplo para comprimir 1 sólo archivo. Con lo cual no hacemos mucho.

Buscando por Internet nos encontramos con nuestros amigos de CodePlex, que comparten con todos nosotros un paquete de código abierto llamado SevenZipSharp. Esta va a ser la librería que usemos en este artículo. Y la cual nos facilitará la vida para la compresión y descompresión. Por tanto nos descargamos su librería.

Ejemplo

El código que se va a mostrar consta de una solución hecha con VS2010 y un proyecto Windows Forms, tal y como se muestra en la siguiente imagen:

ExploradorSolucion

Consta de un formulario Windows y la librería 7z.dll de la cual hablaremos más adelante. Además se agregará la referencia a la librería de SevenZipSharp.

El formulario tiene la siguiente pinta:

Programa

El formulario básicamente toma un directorio del cuadro de texto y lo comprime con el mismo nombre del directorio y con la extensión 7z.

Para ello he quiero añadirle una barra de progreso que nos indique lo que queda por comprimir, ya que la librería facilita este uso.

Por tanto nos vemos en la necesidad de usar la clase BackgroundWorker, donde no me voy a extender mucho en su explicación.

Por tanto cuando se presiona el botón “Comprimir”, iniciaremos el control de ejecución en segundo plano para controlar el avance de la compresión.

private void button2_Click(object sender, EventArgs e)
{
    if (Directory.Exists(this.textBox1.Text))
    {
        progressBar1.Value = 0;
        object[] parametros = new object[] { this.textBox1.Text };
        backgroundWorker1.RunWorkerAsync(parametros);
    }
    else
    {
        MessageBox.Show("El directorio no existe");
    }
}

El componente BackgroundWorker iniciará la compresión:

private void backgroundWorker1_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
    string ficheroSalida = string.Format("{0}.7z", (string)((object[])e.Argument)[0]);
    try
    {
        comp.CompressDirectory((string)((object[])e.Argument)[0], ficheroSalida, true);
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
}

El objeto “comp” es el objeto de la clase SevenZipCompressor que se ha inicializado en el constructor de la clase:

public FormPrueba()
{
    InitializeComponent();
    // Para que funcione correctamente se debe indicar la ruta a la librería 7z.dll, 
    // aqui lo que hago es incluirla en el proyecto y al estar en el mismo directorio no hace falta decírselo
    //string rutaLib = string.Format("{0}\\7z.dll", Application.StartupPath);
    //SevenZipCompressor.SetLibraryPath(rutaLib);
    comp = new SevenZipCompressor();
    comp.CompressionFinished += new EventHandler<EventArgs>(comp_CompressionFinished);
    comp.Compressing += new EventHandler<ProgressEventArgs>(comp_Compressing);
}

Además se están controlando los eventos de finalización y compresión de la clase SevenZipCompressor. De tal forma que al finalizar el proceso mostraremos al usuario un mensaje diciendo que ha finalizado. Y a medida que se van comprimiendo los ficheros usaremos la barra de progreso del formulario con el siguiente código:

void comp_Compressing(object sender, ProgressEventArgs e)
{
    try
    {
        backgroundWorker1.ReportProgress(e.PercentDone);
    }
    catch (Exception ex)
    {
        string parada = ex.Message;
    }
}

private void backgroundWorker1_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e)
{
    this.progressBar1.Value = e.ProgressPercentage;
}

Lo único que cabe destacar es la inclusión de la librería de 7zip dentro del proyecto. Esto se debe a que de otra forma tenemos que indicar a la librería SevenZip la ruta de la misma, y de esta forma la encuentra directamente en el directorio de compilación. Para ello recordar que cuando se incluya la librería en el proyecto debes indicarle que se copie en el directorio de resultados.


PropiedadesDll

También tener en cuenta si la versión de instalación de 7zip en vuestro equipo, ya que yo tengo la de 64bit y esto al combinarlo con el proyecto da un error, para ello he tenido que usar la librería de 32bit que os podéis descargar también desde la web.

La solución, por supuesto comprimida con 7zip, la podéis descargar desde aquí el fichero con el nombre “2010WinForm_ComprimiendoFicherosSolution.7z”.

Espero que os sirva de ayuda.

Anuncios

Comentarios en: "Usar compresión SevenZipSharp en .NET" (9)

  1. Enel Almonte dijo:

    Griacias por el articulo!!!!

  2. Alejandro Rosales Colón dijo:

    Muchas gracias por el articulo, me ha servido de mucho pues yo apenas comienzo en la programación en C# y tengo un proyecto en el cual respaldar carpetas de mas de 12 GB de información cada día, pero tengo una duda que no he podido dar con la solución y es que a un maestro como tu será cosa fácil; en el código donde puedo indicar también la ruta en la cual quiero guardar el archivo comprimido usando otro folderBrowserDialog y textbox que ya he agregado y ademas personalizar el nombre del fichero con la fecha de hoy . Muchas gracias por tu atención.

    • Creo que no he entendido bien la pregunta, pero me aventuro a intuirla, creo que preguntas si es posible cambiar el nombre del fichero comprimido por otro indicando la fecha de hoy y además indicarle con un FolderBrowseDialog la ruta donde guardarlo… si es así entonces sin ningún problema:
      string ficheroSalida = string.Format(“{0}.7z”, (string)((object[])e.Argument)[0]);
      En vez de eso ponle lo que tú quieras al “string.Format” como un “DateTime.Now.ToString” formateado y también puedes pasar más de un argumento a “object[] parametros” y ahí le puede incluir otro indicándole la ruta de salida. Si ves que no era la respuesta a tu pregunta me lo vuelves a explicar y lo vemos.
      Suerte.

      • Alejandro Rosales Colón dijo:

        muchas gracias por tu pronta respuesta ya he podido formatear el nombre final con:

        string ficheroSalida = string.Format(“Backup_” + DateTime.Now.ToString(“dd_MM_yyyy”) + “.7z”, (string)((object[])e.Argument)[0]);

        pero aun no entiendo como agregarle el argumento a esa linea para que tome el texto del textbox_destino

      • Fácil, rápido y para toda la familia:
        object[] parametros = new object[] { this.textBox1.Text, textbox_destino.Text };
        Luego lo tendrás disponible en el método “backgroundWorker1_DoWork” como segundo argumento:
        (string)((object[])e.Argument)[1]
        y lo tendrás que tratar en tu String.Format para formar la ruta de la variable “ficheroSalida”.
        Te podría poner el código completo, pero entonces ya te haría yo todo el trabajo 😉
        Ánimo y seguro que lo consigues, ya me contarás.

      • Alejandro Rosales Colón dijo:

        Mira lo he logrado asi:

        string ficheroSalida = ((object[])e.Argument)[1] + string.Format(@”\Backup_” + DateTime.Now.ToString(“dd_MM_yyyy”) + “.7z”, (string)((object[])e.Argument)[0]);

        ¿es correcto?

        Veras, no soy muy bueno en la programación pero desde que descubri este lenguaje hace tres meses dia a dia me apasiona más aprender cosas nuevas acerca de el y desarrollar pequeñas aplicaciones para mi ambito laboral, de verdad muchas gracias.

        Aprovechando la gran ayuda que me haz brindado fíjate tambien que no he podido cancelar la operación en segundo plano del backgroundWorker1, he programado un botón para cancelarlo con backgroundWorker1.CancelAsync(); pero no realiza la cancelación, ya he modificado la propiedad backgroundWorker1.WorkerSupportsCancellation a true; pero nadamas no le encuentro 😦 ¿que crees podria ser?

  3. Alejandro Rosales Colón dijo:

    Me he fijado bien en el código y ya lo he acomodado mejor :

    string ficheroSalida = string.Format((string)((object[])e.Argument)[1] + @”\Backup_” + DateTime.Now.ToString(“dd_MM_yyyy”) + “.7z”, (string)((object[])e.Argument)[0]);

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s

A %d blogueros les gusta esto: