Testeando XE2… (soporte nativo para ficheros ZIP)
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).
// 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:
// 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:
// extraerlos todos hacia un directorio procedure ExtractAll(Path: string = ''); |
Añadir ficheros a un archivo comprimido existente:
// 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).
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.
Por ejemplo, el código para extraer todo el contenido sobre un directorio seleccionado es el siguiente:
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:
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.
Un saludo.
Embarcadero MVP.
Analista y Programador de Sistemas Informáticos.
Estudios de Informática (Ingeniería Técnica Superior) en la UPC (Universidad Politécnica de Barcelona).
Llevo utilizando Delphi desde su versión 3. Especialista en diseño de componentes, Bases de Datos, Frameworks de Persistencia, Integración Continua, Desarrollo móvil,…
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)
@Ñ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…
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?
@Ñ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.
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.
@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.
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.
@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.
la fecha no te la pone bien alguien podra arreglarlo?? y que te de la medida en mega Bytes plis
@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.
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
@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.
@Germán Estévez
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.
@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.
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
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.