7zip y Delphi

7ziplogoHoy me dí a la tarea de buscar la manera de trabajar con archivos 7zip desde Delphi.

Encontré así la biblioteca d7zip, publicada bajo licencia MPL1.1, lo cual en pocas palabras, nos permite hacer uso de ella en proyectos libres o privativos.

A pesar de que la biblioteca no ha publicado nuevas versiones desde Abril del 2010 (v.1.2), el log de SVN muestra alguna actividad aún en noviembre del 2011 y es compatible con las últimas versiones de Delphi, lo cuál me pareció aceptable para considerarlo un proyecto vivo.

Antes de decidirme a utilizarla, quise comprobar si encontraría algún problema para compilar y ejecutar aplicaciones de 64 bits con esta, tomando en cuenta que la descarga incluye únicamente la versión de 32 bits para el archivo 7z.dll (versión 4.65).

Luego de buscar un rato entre las descargas del proyecto siete-zip y valorar varias opciones, hice una prueba con la última versión estable disponible a la fecha (la 9.20) de la biblioteca, tanto en 32 como de 64 bits. Hasta ahora he trabajado poco a nivel de API con 7-zip y, la verdad, no conozco a ciencia cierta su grado de compatibilidad hacia atrás. En la página de descargas de 7-zip, el archivo es el que tiene la descripción Libreria 7z, SFXs para instaladores, Enchufe para manejador FAR.

Preparé un simple proyecto de prueba, primero para solo obtener la lista de los archivos incluidos en un archivo 7z:

uses sevenzip;

procedure TForm1.Button1Click(Sender: TObject);
var
  Arch: I7zInArchive;
  I: Integer;
begin
  if od7z.Execute then  //od7z is TOpenDialog
  begin
    Memo1.Lines.Clear;
    Memo1.Lines.Add(TPath.GetFileName(od7z.FileName));
    Memo1.Lines.Add(StringOfChar('=', 30));
    try
      Arch := CreateInArchive(CLSID_CFormat7z, '7za.dll');
      Arch.OpenFile(od7z.FileName);
      for I := 0 to Arch.NumberOfItems - 1 do
        if not Arch.ItemIsFolder[I] then
          Memo1.Lines.Add(Arch.ItemPath[I]);
    except
      on E:Exception do
      begin
        Memo1.Lines.Add(Format('ERROR: [%s] %s', [E.ClassName, E.Message]));
        raise;
      end;
    end;
  end;
end;

El resultado fue satisfactorio en ambas plataformas.

7zlist

Luego, he ampliado el ejemplo para comprimir algunos archivos:

procedure TForm1.Button2Click(Sender: TObject);
var
   Arch: I7zOutArchive;
   AFileName: string;
begin
  if odAll.Execute and sd7z.Execute then
  begin
    Arch := CreateOutArchive(CLSID_CFormat7z, '7za.dll');
    SetCompressionLevel(Arch, 9);
    SevenZipSetCompressionMethod(Arch, m7LZMA);
    if eContraseña.Text <> '' then
      Arch.SetPassword(eContraseña.Text);
    Memo1.Lines.Clear;
    for AFileName in odAll.Files do
    begin
      Arch.AddFile(AFileName, '');
      Memo1.Lines.Add(AFileName);
      Memo1.Update;
    end;
    Memo1.Lines.Add(StringOfChar('=', 30));
    Memo1.Lines.Add('Finalizado');
    Arch.SaveToFile(sd7z.FileName);
  end;
end;

Los ejemplos son, intencionalmente, bastante sencillos, pues la idea es solamente comprobar la compatibilidad.

Consideraciones

  • No he probado más allá de lo que comento en la entrada esta biblioteca con las versiones recientes de la DLL, aunque hasta ahora todo va bien, el que todo funcione realmente depende del grado de compatibilidad hacia atrás mantenido en la dll misma por el proyecto 7-zip.
  • Estoy usando el código de la última revisión de d7zip, que está disponible solo vía svn checkout.
  • He encontrado que es suficiente utilizar el archivo 7za.dll, que es más pequeño que el 7z.dll, por tanto he incluido en la llamada a CreateInArchive/CreateOutArchive el parámetro adicional (lib) ’7za.dll’. Este parámetro existe únicamente en la última revisión, comentada en el punto anterior. Me decidí a probar con 7za.dll porque el código pascal declara una serie de interfaces y leí en las FAQ que 7za.dll trabaja usando interfaces COM. Honestamente desconozco si la versión actual de 7z.dll incluye también el contenido de 7za.dll o si la versión de 7z.dll incluida en la descarga de d7zip es la estándar que también se descarga de sourceforge.
  • La DLL debe estar accesible al ejecutable. Yo he colocado la dll de 32 bits en la carpeta win32/debug y la dll de 64 bits en la carpeta win64/debug.
  • La unidad sevenzip.pas colisiona con una unidad del mismo nombre del proyecto jedi. Si usas JCL/JVCL debes tener en cuenta el orden de las carpetas de búsqueda en tu search path o bien incluir el sevenzip.pas como parte de tu proyecto, tal como he hecho yo en el ejemplo

Descargas

Lecturas recomendadas

Hace algún tiempo, Neftalí —Germán Estévez— nos hablaba sobre el soporte nativo para ficheros ZIP incluido a partir de Delphi XE2, que también podría ser la solución a tus necesidades de compresión.

¿Te gusta el contenido?

About these ads

5 Respuestas a “7zip y Delphi

  1. La libreria JCL tiene soporte excelente a 7zip en la unidad JclCompression..

  2. Muy buen artículo amigo jach y me parece muy útil el componente (aunque ya sabes que no soy muy dado a usar componentes de terceras partes), de cualquier forma creo que será uno de los pocos componentes que usaré.

    Saludos

  3. Pingback: The Hacker’s Corner » Blog Archive » MVP Nuggets #3

  4. Hola Juan Antonio.
    Hace ya un tiempo que publicaste esta entrada y uno nunca va a saber cuando le puede hacer falta la información. Justo hoy me ha llegado un proyecto en el que necesito descomprimir un 7z.
    Gracias. ;-)

    Un saludo.

  5. William Gabriel Ferro

    Gracias, tus publicaciones me han servido de mucho.

Deja un comentario

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