Inicio > Delphi, Ejemplos, XE2 > Testeando XE2… (soporte nativo para ficheros ZIP)

Testeando XE2… (soporte nativo para ficheros ZIP)

Miércoles, 14 de Septiembre de 2011 Dejar un comentario Ir a comentarios
Share Button

ZIPFile   Otra de las nuevas funcionalidades que trae la versión de XE2 es el soporte para ficheros ZIP. No es que sea especialmente transcendental, pero en mi caso la he utilizado bastante en mis desarrollos y hasta ahora lo había tenido que hacer mediante componentes externos (he  probado varios paquetes).

   Para ello se ha añadido a la unit System.ZIP, todo lo necesario para el trabajo con este tipo de ficheros.

   En sistema de trabajo es bastante sencillo. Para trabajar con un fichero de este tipo tenemos que crear un objeto de la clase TZIPFile y abrirlo (utilizando la función Open). Tenemos diferentes modos de apertura dependiendo de las operaciones a realizar con el fichero (read,write o readwrite).

0
1
2
// Abrir un fichero
procedure Open(ZipFileName: string; OpenMode: TZipMode); overload;
procedure Open(ZipFileStream: TStream; OpenMode: TZipMode); overload;

Una vez abierto el fichero, podemos utilizar las operaciones básicas.
Extraer ficheros existentes dentro del archivo:

0
1
2
3
4
// Extraer un fichero sobre una ubicación
procedure Extract(FileName: string; Path: string = '';
                  CreateSubdirs: Boolean=True); overload;
procedure Extract(Index: Integer; Path: string = '';
                  CreateSubdirs: Boolean=True); overload;

O extraerlos todos:

0
1
// extraerlos todos hacia un directorio
procedure ExtractAll(Path: string = '');

Añadir ficheros a un archivo comprimido existente:

0
1
2
// Añadir ficheros a un archivo comprimido
procedure Add(FileName: string; ArchiveFileName: string = '';
              Compression: TZipCompression = zcDeflate); overload;

(esta tienen bastantes variantes sobrecargadas con diferentes parámetros)

Y también podemos comprobar la integridad de un fichero comprimido existente mediante la función IsValid (que en este caso está definida como función de clase).

0
class function IsValid(ZipFileName: string): Boolean; static;

No son todas las funciones, pero sí las básicas; También hay algunas más definidas como procedimientos de clase, que nos permiten realizar operaciones de forma más sencilla y/o rápida.

Para ponerlo en práctica y probarlo he realizado un sencillo ejemplo que incluye las operaciones básicas; Y podéis comprobar que con pocas líneas es fácil hacer casi todo lo que se espera de estos ficheros.

 

TestZIPFile

Por ejemplo, el código para extraer todo el contenido sobre un directorio seleccionado es el siguiente:

0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
procedure TForm3.ActionExtractExecute(Sender: TObject);
var
  b:boolean;
  DirOut:String;
begin
  // El nombre es vacío?
  if (zipFileName = '') then begin
    // Abrir uno
    ActionOpen.Execute;
    // Correcto?
    if (zipFileName = '') then begin
      Exit;
    end;
  end;
 
  // Es Valido
  b := xf.IsValid(zipFileName);
 
  // no correcto?
  if not (b) then begin
    MessageDlg('Error al abrir el fichero. Parece que es' +
               ' incorrecto o está corrupto.',
               mtError, [mbOK], 0);
    exit;
  end;
 
  // Extraer  // Path de salida
  b := SelectDirectory('Seleccione el directorio para extraer ficheros',
                       '', DirOut);
  if (b) then begin
    // protección
    try
      // Extraer al directorio seleccionado
      xf.Open(zipFileName, zmRead);
      xf.ExtractAll(DirOut);
      xf.Close;
      MessageDlg('La extracción se ha producido correctamente',
        mtInformation, [mbOK], 0);
    except
      MessageDlg('Se ha producido un error al extraer los ficheros.',
        mtError, [mbOK], 0);
    end;
  end;
end;

El código para añadir uno o varios ficheros seleccionados en un OpenDialog sería similar a este:

0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
procedure TForm3.ActionAddFilesExecute(Sender: TObject);
var
  b:Boolean;
  i:integer;
begin
 
  // No está creado?
  if not Assigned(xf) then begin
    // Si no lo está lo creamos
    ActionNuevoZIPExecute(nil);
  end;
  // Selecciconar ficheros a añadir
  b :=  OpenDialog1.Execute;
  if (b) then begin
    // Abrirlo
    xf.Open(zipFileName, zmReadWrite);
 
    // Para 1 fichero
    //     xf.Add(OpenDialog1.FileName);
 
    // Para n ficheros
    for i := 0 to (OpenDialog1.Files.Count - 1) do begin
      xf.Add(OpenDialog1.Files[i]);
    end;
    // cerrar
    xf.Close;
  end;
  // Actualizar la pantalla
  _UpdateFiles();
end;

Para cada fichero que hay incluído en un archivo ZIP contamos con una estructura que nos permite acceder a todas la información de forma rápida. Definido como packed record, en System.ZIP podéis encontrar la definición completa y la documentación de esta estructura:

Podéis revisar el código completo del ejemplo; Está disponible aquí y podéis descargarlo junto con el fichero  compilado.

[SOURCES + BIN]

Un saludo.

Share Button
Categories: Delphi, Ejemplos, XE2 Tags: , , ,
  1. Jueves, 15 de Septiembre de 2011 a las 08:56 | #1

    No está mal, pero es incómodo. Prefiero el soporte para TAR y GZip que tiene Free Pascal (http://lazarus-ccr.sourceforge.net/fpcdoc/fcl/libtar/ y http://lazarus-ccr.sourceforge.net/fpcdoc/fcl/zstream/ respectivamente), que te permiten acceder al contenido de paquetes .tar y .tar.gz usando TStream, sin tener que extraer previamente los archivos.

    Estaría bien que Delphi lo incluyera, en especial si realmente quiere hacerse un hueco en los sistemas POSIX (creo que MacOS también tiene soporte nativo para TAR y GZip)

  2. Neftalí
    Jueves, 15 de Septiembre de 2011 a las 09:05 | #2

    @Ñuño Martínez
    Aunque he puesto las cabeceras de algunas funciones, no he colocado todas las que hay en la unit System.ZIP. Entre las que no he puesto, se encuentran algunas para trabajar también con Streams.

    El tema de los diferentes formatos, pues supongo que como todo; Hay que tener en cuenta que es una primera versión.
    Esperemos, que como en otros muchos aspectos, la cosas se vayan ampliando…

  3. Jueves, 15 de Septiembre de 2011 a las 10:56 | #3

    Amigo, si la clase tiene métodos para acceder a un archivo concreto para leerlo con un TStream, entonces mi queja es menor. Y si también permite insertar datos del mismo modo, pues entonces grito todavía menos.

    Sólo queda, entonces, lo del formato, Pero eso ya es otro tema. En última instancia siempre se puede adaptar las clases de la FCL a Delphi, ¿no?

  4. Neftalí
    Jueves, 15 de Septiembre de 2011 a las 11:39 | #4

    @Ñuño Martínez
    Sí que los tiene sí.
    No los puse por no colocar todos, pero tanpo para añadir como para extraer están.

  5. German
    Martes, 20 de Septiembre de 2011 a las 06:48 | #5

    Creo que la única pega que pondría sobre esta clase sería los eventos… ya que no dispone de ninguno y es imposible mostrar una barra de proceso, totalmente necesaria en mi opinión, para trabajar con archivos grandes.

    Salu2.

  6. Neftalí
    Martes, 20 de Septiembre de 2011 a las 09:15 | #6

    @German
    Hola Germán.
    Efectívamente. Como ya he comentado es un paquete básico. Válido seguramente para la mayoría de ocasiones, pero no para todas.

    Un saludo.

  7. Alejandro
    Miércoles, 9 de Enero de 2013 a las 18:58 | #7

    Amigo Neftalí, que paquetes has probado para el manejo de archivos comprimidos. Necesito manejar esos archivos usando la versión 10 de Delphi.

    Espero que me puedas recomendar alguno que sea relativamente bueno y en lo posible gratis.

  8. Neftalí
    Miércoles, 9 de Enero de 2013 a las 19:17 | #8

    @Alejandro
    Hola Alejandro.
    A parte de este comentado en el artículo, he utilizado durante mucho tiempo ZipMaster (http://www.delphizip.org/) que creo que es compatible con todas las versiones de delphi y posee las acciones necesarias para realizar todo lo que necesites con ficheros comprimidos.
    Es este entrada del blog de Juan Antonio Castillo también tienes información sobre otro paquete (http://jachguate.wordpress.com/2012/12/10/7zip-y-delphi/)

    Un saludo.

  9. joan
    Jueves, 18 de Abril de 2013 a las 14:36 | #9

    la fecha no te la pone bien alguien podra arreglarlo?? y que te de la medida en mega Bytes plis

  10. Neftalí
    Jueves, 18 de Abril de 2013 a las 15:14 | #10

    @joan
    ¿Puedes explicarte mejor Joan?
    ¿Podrías poner un ejemplo del error?
    Se puede mirar en QC para ver si es un bug conocido y si hay solución publicada.

  11. Juan Labrador
    Martes, 25 de Febrero de 2014 a las 10:16 | #11

    Hola:
    Tengo un problema que espero me puedas ayudar. He hecho un programita para copiar ficheros en ZIP y funciona muy bien. El problema es que sí el fichero generado es mayor de 4 GB da un error al intentar abrirlo.
    Cuando abro el fichero con 7-zip veo en las propiedades de cada fichero que aparece Host OS: FAT. Por el contrario, sí creo un fichero directamente (enviar a carpeta comprimida en zip) el Host OS: aparece como NTFS.
    He indagado el fichero System.Zip.pas y creo que tiene que ver con LocalHeader.MadeByVersion que debería ser 10 (NTFS).
    Gracias

  12. Neftalí
    Martes, 25 de Febrero de 2014 a las 11:02 | #12

    @Juan Labrador
    Hola Juan.
    Es posible que tenga que ver con la limitación de tamaño de ficheros grandes en FAT.
    Tal vez deberías revisar las opciones para ver si puedes forzar a que los ficheros grandes se compriman utilizando la cabecera NTFS.

    Un saludo.

  13. Juan Labrador
    Martes, 25 de Febrero de 2014 a las 13:44 | #13

    @Neftalí
    Muchas gracias por tu rápida respuesta. El problema es ese seguro pero no veo cómo decir que sea NTFS. En mi desesperación he compilado incluso una versión 64 y ejecutada en un Server 2008 pero también los hace FAT.
    No se sí podria “rehacer” System.Zip.dcu editando System.Zip.pas y forzar el valor a 10.

  14. Neftalí
    Martes, 25 de Febrero de 2014 a las 16:10 | #14

    @Juan Labrador
    Uno de los métodos Add que provee la clase:

    ———————————————————————-
    procedure TZipFile.Add(Data: TStream; LocalHeader: TZipHeader; CentralHeader: PZipHeader);
    ———————————————————————-

    Permite pasar información de LocalHeader, que contiene la propiedad que comentas.
    Lo que ya no será si realmente será lo que necesitas. Siento por poder ayudarte con algo más concreto.

    Un saludo.

  15. Juan Labrador
    Miércoles, 26 de Febrero de 2014 a las 10:22 | #15

    Tengo la variable Fichero como TZipFile
    Para añadir ficheros creo primero una lista de ficheros en un listbox (Ficheros) y luego hago un try para añadirlos uno a uno con
    Fichero.Add(Ficheros.Items[J],Ficheros.Items[J],zcStored);
    Así funciona bien pues de otro modo incluye todos en el raiz del fichero zip
    El problema es que Fichero.FileInfo[J].MadeByVersion es de solo lectura y siempre los comprime como FAT, limitando el tamaño del archivo comprimido a 4 GB

  16. Juan Labrador
    Miércoles, 26 de Febrero de 2014 a las 10:39 | #16

    Buscando he visto el enlace http://www.gzip.org/#faq10
    Tal vez sea este el problema. Yo tengo la versión X3, puede que la X5 lo tenga solucionado.

  1. Lunes, 10 de Diciembre de 2012 a las 07:17 | #1
What is 19 + 13 ?
Please leave these two fields as-is:
IMPORTANTE! Para continuar, debes contestar la pregunta anterior (para evitar SPAM) :-)