Anda di halaman 1dari 8

Compresin y Decompresin de archivos

ZIP con Java


archivos JAR. Pero, an ms til, tambin podemos encontrar todo un paquete conteniendo
clases que nos permiten agregar compresin ZIP y GZIP a nuestras aplicaciones.
A travs del paquete java.util.zip, Sun nos ofrece las siguientes funcionalidades:
Compresin, Decompresin, y Visualizacin de archivos ZIP y GZIP
Compresin y Decompresin usando el algoritmo de compresin DEFLATE (usado
por ZIP y GZIP)
Clases de utilidad para calcular checksums CRC-32 y Adler-32
Compresin ZIP
Para permitirnos comprimir mltiples archivos en un solo archivo ZIP, Java nos provee de dos
clases:
java.util.zip.ZipOutputStream: un wrapper output stream que sabe cmo escribir
en un stream destino (usualmente un archivo) aplicando compresin ZIP.
java.util.zip.ZipEntry: usado para identi!car la ubicacin (path) en un archivo ZIP
hacia donde el archivo comprimido ser escrito.
Los pasos requeridos para comprimir archivos en un archivo ZIP son los siguientes:
Crear un ZipOutputStream que referencia el destino (por ejemplo, puede
referenciar a un archivo al wrapear un java.io.FileOutputStream)
Crear un java.io.InputStream (o derivado) que referencia un archivo a agregar
al ZIP
Crear una ZipEntry que representa el InputStream creado en el paso 2
Agregar el ZipEntry al ZipOutputStream llamando a su mtodo
Java nos provee la herramienta JAR (en el directorio bin/ del JRE) para crear, ver, y extraer
putNextEntry()
Copiar datos del InputStream al ZipOutputStream (usando un bu"er array de
bytes para leer desde el InputStream y luego escribirlo en el ZipOutputStream)
La clave para crear una compresin de mltiples archivos radica en ZipEntry. El ZipEntry
nos permite setear un path lgico dentro del archivo donde el siguiente conjunto de datos
binarios ser escrito. Luego, cuando el archivo es descomprimido, tiene que recrear la
ubicacin destino y extraer la entrada all mismo.
La siguiente porcin de cdigo ejempli!ca como comprimir una java.util.List de
nombres de archivos a un archivo ZIP destino filename.
try
{
// Reference to the file we will be adding to the zipfile
BufferedInputStream origin = null;
// Reference to our zip file
FileOutputStream dest = new FileOutputStream( filename );
// Wrap our destination zipfile with a ZipOutputStream
ZipOutputStream out = new ZipOutputStream(
new BufferedOutputStream( dest ) );
// Create a byte[] buffer that we will read data
// from the source
// files into and then transfer it to the zip file
byte[] data = new byte[ BUFFER_SIZE ];
// Iterate over all of the files in our list
for( Iterator i=files.iterator(); i.hasNext(); )
{
// Get a BufferedInputStream that we can use to read the
// source file
String filename = ( String )i.next();
System.out.println( "Adding: " + filename );
FileInputStream fi = new FileInputStream( filename );
origin = new BufferedInputStream( fi, BUFFER_SIZE );
// Setup the entry in the zip file
ZipEntry entry = new ZipEntry( filename );
out.putNextEntry( entry );
// Read data from the source file and write it out to the zip file
int count;
while( ( count = origin.read(data, 0, BUFFER_SIZE ) ) != -1 )
{
out.write(data, 0, count);
}
// Close the source file
origin.close();
}
// Close the zip file
out.close();
}
catch( Exception e )
{
e.printStackTrace();
}
En este cdigo, tenemos una java.util.List contieniendo Strings con el path completo a
los archivos a agregar en el ZIP. Una ZipEntry es agregada al ZipOutputStream para cada
archivo. El archivo es ledo al crear un nuevo FileInputStream, referencindolo y
wrapendolo con un BufferedInputStream. Los datos son luego ledos desde el archivo
fuente en bloques de tamao BUFFER_SIZE y escritos al ZipOutputStream. Luego de que el
archivo ha sido copiado completamente al ZipOutputStream, se cierra, y el siguiente archivo
es procesado. Esto continina hasta que no hay ms archivos por procesar. Finalmente, el
ZipOutputStream se cierra y la operacin es !nalizada.
Decompresin ZIP
La decompresin es justamente lo opuesto a la compresin (obviamente, pero me estoy
re!riendo a las operaciones de programacin!). Leemos un archivo comprimido con ZIP
utilizando java.util.ZipInputStream y navegamos a travs de su conjunto de ZipEntrys.
Los pasos son los siguientes:
Crear un java.util.zip.ZipInputStream que referencia a la fuente
comprimida (por ejemplo, para leer un archivo debemos hacer que el
ZipInputStream wrapee un java.io.FileInputStream)
Iterar sobre todas las ZipEntrys contenidas en el archivo al llamar al mtodo
getNextEntry() de ZipInputStream
Crear un java.io.OutputStream que referencia el destino (por ejemplo, un
FileOutputStream) que coincide con el path del ZipEntry
Copiar los datos desde el ZipInputStream hacia el OutputStream, hasta que el
stream !nalize (esto seala el !n del ZipEntry)
Cerrar el OutputStream
Obtener el siguiente ZipEntry (volviendo al paso 2)
La siguiente porcin de cdigo muestra cmo descomprimir archivos de un archivo ZIP hacia
sus ubicaciones apropiadas en el sistema de archivo. Asume que el nombre del archivo ZIP ha
sido especi!cado a travs de filename, y que el directorio destino ha sido especi!cado con
destination.
try {
// Create a ZipInputStream to read the zip file
BufferedOutputStream dest = null;
FileInputStream fis = new FileInputStream( filename );
ZipInputStream zis = new ZipInputStream(
new BufferedInputStream( fis ) );
// Loop over all of the entries in the zip file
int count;
byte data[] = new byte[ BUFFER_SIZE ];
ZipEntry entry;
while( ( entry = zis.getNextEntry() ) != null )
{
if( !entry.isDirectory() )
{
String entryName = entry.getName();
prepareFileDirectories( destination, entryName );
String destFN = destination + File.separator + entry.getName();
// Write the file to the file system
FileOutputStream fos = new FileOutputStream( destFN );
dest = new BufferedOutputStream( fos, BUFFER_SIZE );
while( (count = zis.read( data, 0, BUFFER_SIZE ) ) != -1 )
{
dest.write( data, 0, count );
}
dest.flush();
dest.close();
}
}
zis.close();
}
catch( Exception e )
{
e.printStackTrace();
}
Como en el ejemplo anterior, BUFFER_SIZE puede ser 8192 (8 K), pero esta con!guracin
puede ser cambiada a gusto. El mtodo getName() de ZipEntry retorna el nombre
completo, incluyendo el path, hacia el archivo destino.
Un mtodo de ayuda asegura que el directorio existe (o lo crea si no existe) antes de escribir el
archivo de salida:
prepareFileDirectories()
Visualizacin de ZIP
Comparado a la decompresin de archivos ZIP, la visualizacin de los contenidos es casi tan
trivial. Todo lo que necesitamos hacer es crear un ZipInputStream, apuntarlo a nuestro
archivo ZIP, e iterar sobre los ZipEntrys sin necesidad de extraer nada. La siguiente porcin
de cdigo lo ejempli!ca.
try
{
FileInputStream fis =
new FileInputStream( this.filename );
ZipInputStream zis = new ZipInputStream(
new BufferedInputStream( fis ) );
// Loop over all of the entries in the zip file
ZipEntry entry;
DateFormat df = DateFormat.getDateTimeInstance(
DateFormat.SHORT, DateFormat.SHORT );
while( ( entry = zis.getNextEntry() ) != null )
{
if( !entry.isDirectory() )
{
System.out.println( entry.getName() + ", " +
df.format( new Date( entry.getTime() ) ) + ", " +
entry.getSize() + ", " + entry.getCompressedSize() );
}
}
}
catch( Exception e )
{
e.printStackTrace();
}
Este cdigo asume que el archivo ZIP est representado por filename. Crea un
FileInputStream que referencia al archivo, lo wrapea con un ZipInputStream, y luego
itera sobre los contenidos usando el mtodo getNextEntry() de ZipInputStream. Luego
muestra informacin del archivo utilizando un sobconjunto de la informacin que provee la
clase ZipEntry.
He aqu lo que podemos encontrar en la clase ZipEntry:
String getComment(): Retorna el comentario para la entrada, o null si no posee.
long getCompressedSize(): Retorna el tamao de los datos comprimidos para la
entrada, o -1 si es desconocido.
long getCrc(): Retorna el checksum CRC-32 de los datos de la entrada descomprimida, o
-1 si es desconocido.
byte[] getExtra(): Retorna la informacin extra para esta entrada, o null si no posee.
int getMethod(): Retorna el mtodo de compresin para esta entrada, o -1 si no est
especi!cado.
String getName(): Retorna el nombre de la entrada.
long getSize(): Retorna el tamao descomprimido de los datos de entrada, o -1 si es
desconocido.
long getTime(): Retorna la fecha y hora de modi!cacin de la entrada, o -1 si no est
especi!cado.
boolean isDirectory(): Retorna true si esta es una entrada de directorio.

Anda mungkin juga menyukai