15
 Compresión y descompresión de datos utilizando Java 1 Compresión y descompresión de datos utilizando Java Autor: Qusay H. Mahmoud/Konstantin Kladko Traducción/Adaptación:  RuGI URL Original: http://developer.java.sun.com/developer/technicalArticles/Programming/compressio n / Muchas fuentes de información contienen datos redundantes o datos que no son muy revelantes para la información que se quiere guardar. Esto produce grandes cantidades de datos que se transfieren entre el cliente y el servidor de aplicaciones o entre computadoras en general. La solución obvia a estos problemas de almacenamiento de los datos y traslado de la información es instalar dispositivos del almacenamiento adicionales y extender los medios de comunicación existentes. Hacer esto, sin embargo, requiere un incremento en los costos de operación en una organización. Un método para reducir una porción el almacenamiento de los datos y la tranferencia de la información es a través de representaciones de los datos con un codigo mas eficiente. Este artículo presenta una ligera introducción a la compresion y descompresion de datos, y muestra cómo comprimir y descomprimir estos, eficaz y convenientemente, desde tus aplicaciones Java usando el paquete java.util.zip Mientras qué es posible comprimir y descomprimir datos usando herramientas como WinZip, gzip, y JAR, éstas se usan como aplicaciones aisladas. Es posible invocar estas herramientas desde tus aplicaciones Java, pero ésta no es un manera correcta de utilizarlas y no es una solución eficaz. Este artículo: Muestra brevemente las generalidades de la compresión de datos Describe el paquete java.util.zip Muestra cómo usar este paquete para comprimir y descomprimir datos Muestras cómo comprimir y descomprimir objetos serializados para ahorrar espacio en disco Muestras cómo comprimir y descomprimir datos al vuelo (antes de transmitir) para mejorar el desempeño de aplicaciones cliente/servidor Generalidades de la compresión de datos Un ejemplo sencillo de redundancia de datos en un archivo es la repetición de caracteres. Por ejemplo, considera la siguiente cadena: BBBBHHDDXXXXKKKKWWZZZZ Este cadena puede ser codificada y compactada reemplazando cada subcadena repetida de carácteres por un solo carácter repetido y un número que representa el número de veces que el carácter se repite. La cadena anterior puede codificarse así: 4B2H2D4X4K2W4Z 

comprimir

Embed Size (px)

Citation preview

Page 1: comprimir

5/9/2018 comprimir - slidepdf.com

http://slidepdf.com/reader/full/comprimir 1/15

 

Compresión y descompresión de datos utilizando Java

1

Compresión y descompresión de datosutilizando Java

Autor: Qusay H. Mahmoud/Konstantin KladkoTraducción/Adaptación: RuGI

URLOriginal:http://developer.java.sun.com/developer/technicalArticles/Programming/compression/  

Muchas fuentes de información contienen datos redundantes o datos que no son muyrevelantes para la información que se quiere guardar. Esto produce grandes cantidades dedatos que se transfieren entre el cliente y el servidor de aplicaciones o entre computadoras en

general. La solución obvia a estos problemas de almacenamiento de los datos y traslado de lainformación es instalar dispositivos del almacenamiento adicionales y extender los medios de

comunicación existentes. Hacer esto, sin embargo, requiere un incremento en los costos deoperación en una organización. Un método para reducir una porción el almacenamiento de losdatos y la tranferencia de la información es a través de representaciones de los datos con un

codigo mas eficiente. Este artículo presenta una ligera introducción a la compresion ydescompresion de datos, y muestra cómo comprimir y descomprimir estos, eficaz y

convenientemente, desde tus aplicaciones Java usando el paquete java.util.zip 

Mientras qué es posible comprimir y descomprimir datos usando herramientas como WinZip,

gzip, y JAR, éstas se usan como aplicaciones aisladas. Es posible invocar estas herramientas

desde tus aplicaciones Java, pero ésta no es un manera correcta de utilizarlas y no es unasolución eficaz. Este artículo:

• Muestra brevemente las generalidades de la compresión de datos

• Describe el paquete java.util.zip

• Muestra cómo usar este paquete para comprimir y descomprimir datos• Muestras cómo comprimir y descomprimir objetos serializados para ahorrar espacio

en disco• Muestras cómo comprimir y descomprimir datos al vuelo (antes de transmitir) para

mejorar el desempeño de aplicaciones cliente/servidor

Generalidades de la compresión de datos

Un ejemplo sencillo de redundancia de datos en un archivo es la repetición de caracteres. Porejemplo, considera la siguiente cadena:

BBBBHHDDXXXXKKKKWWZZZZ  

Este cadena puede ser codificada y compactada reemplazando cada subcadena repetida decarácteres por un solo carácter repetido y un número que representa el número de veces que el

carácter se repite. La cadena anterior puede codificarse así:

4B2H2D4X4K2W4Z 

Page 2: comprimir

5/9/2018 comprimir - slidepdf.com

http://slidepdf.com/reader/full/comprimir 2/15

 

http://www.javahispano.com

2

Aqui, "4B" significa cuatro B's, "2H" significa dos H's, y asi sucesivamente. La compresiónde cadenas con este algoritmo se conoce somo RLE (run-length encoding)

Como otro ejemplo, considera el almacenamiento de una imagen rectangular. Como unasencilla imagen de un mapa de bits, ésta se puede almacenar como muestra la Figura 1.

0000000000000000000000000000000000000000

00000000000000000000000000000000000000000000000000111111111111111111110000000000

000000000010000000000000000001000000000000000000001000000000000000000100000000000000000000100000000000000000010000000000

00000000001111111111111111111100000000000000000000000000000000000000000000000000

Fig.1. Un mapa de bits con información para el RLE

Otro manera podría ser guardar la imagen como un metafile gráfico:

Rectangle 11, 3, 20, 5 

Que significa; el rectángulo comienza en la coordenada (11,3) y tiene 20 pixeles de ancho y 5

de alto.

La imagen rectangular puede comprimirse utilizando RLE a través del conteo de bitsidenticos, así:

0, 400, 40

0,10 1,20 0,10

0,10 1,1 0,18 1,1 0,10

0,10 1,1 0,18 1,1 0,10

0,10 1,1 0,18 1,1 0,10

0,10 1,20 0,10

0,40 

La primera línea nos dice que la primera línea del mapa de bit's consiste en 40 0's. La terceralínea dice que la tercera línea del mapa de bit's consiste en 10 0's seguidos por 20 1's yseguidos por 10 0's más, y así sucesivamente para las otras líneas.

Nota que RLE requiere representaciones diferentes para el archivo y su versión codificada,

dependiendo del tipo del archivo. Por consiguiente, este método no puede trabajar con todoslos tipos de archivos. Otras técnicas de compresion incluyen variaciones de RLE, una es VLE 

variable-length encoding (también conocida como código Huffman ), y muchas otros. Paramás información, hay muchos libros disponible sobre técnicas de compresion de datos éimagenes.

Hay muchos beneficios con la compresión de los datos. No obtante, la ventaja principal es

reducir requisitos de almacenamiento. También, para comunicaciones de los datos, latransferencia de datos comprimidos aumenta la cantidad de información transmitida. Observa

que la compresión de datos puede implementarse con el hardware ya existente, con software ousando dispositivos de hardware especiales que ya incorporán las técnicas de compresión. LaFigura 2 muestra un diagrama de bloques basico sobre la compresión de datos.

Page 3: comprimir

5/9/2018 comprimir - slidepdf.com

http://slidepdf.com/reader/full/comprimir 3/15

 

Compresión y descompresión de datos utilizando Java

3

_________________

----------------------> Compresion ---------------------->

Datos Originales de Datos comprimidos

<--------------------- datos <---------------------

_________________

Fig.2. Diagrama de Bloques. Compresión de datos

ZIP vs GZIP

Si estás trabajando con Windows, podrías estar familiarizado con la herramienta WinZip quese utiliza para crear un archivo comprimido y para extraer archivos de un archivocomprimido. En UNIX, sin embargo, las cosas se hace de forma ligeramente distinta. El

comando tar se usa para crear un archivo (no comprimido) y otro programa (gzip o

compress) se usa para comprimir el archivo.

El paquete java.util.zip

Java proporciona el paquete java.util.zip para trabajar con archivos compatibles con el

formato zip. este paquete proporciona clases que te permiten leer, crear, y modificar archivoscon los formatos ZIP y GZIP. También te proporciona clases para comprobar las sumas decontrol de flujos de entrada y puede ser usado para validar entradas de datos. Este paquete

proporciona una interface, catorce clases, y dos clases de excepciones como se muestra en laTabla 1.

Tabla 1. El paquete java.util.zip

Elemento Tipo Descripción

Checksum  InterfaceRepresenta un dato de la suma de control (data

checksum). Implementado por las clases Adler32 yCRC32 

Adler32  ClaseUsado para calcular la suma de control(checksum) de

un flujo de datos

CheckedInputStream   ClaseUn flujo de entrada que guarda la suma de control delos datos que estan siendo leídos.

CheckedOutputStream   ClaseUn flujo de salida que guarda la suma de control delos datos que estan siendo escritos.

CRC32  ClaseUsado para calcular la suma de control CRC32 de un

flujo de datos

Deflater  Clase Soporte para compresion usando la librería ZLIB 

DeflaterOutputStream  ClaseUn flujo de salida filtrado para la compresión dedatos con el formato de compresión deflate 

GZIPInputStream  ClaseUn flujo de entrada filtrado para leer datos

comprimidos con el formtatoGZIP

GZIPOutputStream  ClaseUn flujo de salida filtrado para escribir datos

comprimidos con el formato GZIP

Page 4: comprimir

5/9/2018 comprimir - slidepdf.com

http://slidepdf.com/reader/full/comprimir 4/15

 

http://www.javahispano.com

4

Inflater  Clase Soporte para descompresion usando la librería ZLIB 

InflaterInputStream   ClaseUn flujo de entrada filtrado para la descompresion de

datos con el formato de compresión deflate 

ZipEntry  Clase Representa la entrada de un archivo ZIP 

ZipFile  Clase Usado para leer entradas de un archivo ZIP 

ZipInputStream  ClaseUn filtro de entrada para leer archivos con el formatoZIP 

ZipOutputStream  ClaseUn filtro de salida para escribir archivos con el

formato ZIP 

DataFormatException  Clase deexcepcion

Lanza una excepción para señalar un error en elformato de los datos

ZipException Clase de

exepcion

Lanza una excepción para señalar un error en el

formato Zip 

Nota: La librería de compresión ZLIB se desarrolló inicialmente como parte

de la norma PNG(Portable Network Graphics) que no esta protegida porpatentes.

Comprimiendo y descomprimiendo datos desde un archivo ZIP

El paquete java.util.zip proporciona clases para la compresión y descompresión de datos.

La descompresión de un archivo ZIP es solo la lectura de datos desde un flujo de entrada. El

paquete java.util.zip proporciona la clase ZipInputStream para leer archivos ZIP. Un

ZipInputStream se crea como cualquier otro flujo de entrada. Por ejemplo, el siguientefragmento de código se usa para crear un flujo de entrada para leer datos de un archivo con

formato ZIP:

FileInputStream fis = new FileInputStream("figs.zip");

ZipInputStream zin = new

ZipInputStream(new BufferedInputStream(fis));

Una vez creado el flujo de entrada ZIP, puedes leer las entradas del archivo ZIP usando elmétodo getNextEntry que retorna un objeto ZipEntry. Si se alcanza el fin del archivo(EOF)

getNextEntry retorna null:

ZipEntry entry;

while((entry = zin.getNextEntry()) != null) {

// extraer los datos

// abrir flujos de salida

}

Ahora, es momento de preparar un flujo de salida descomprimido, esto se puede hacer de lasiguiente manera:

int BUFFER = 2048;

Page 5: comprimir

5/9/2018 comprimir - slidepdf.com

http://slidepdf.com/reader/full/comprimir 5/15

 

Compresión y descompresión de datos utilizando Java

5

FileOutputStream fos = new

FileOutputStream(entry.getName());

BufferedOutputStream dest = new

BufferedOutputStream(fos, BUFFER);

Nota: En el código anterior se uso BufferedOutputStream en lugar de

ZIPOutputStream. ZipOutputSream y GZIPOutputStream usan un buffer  

interno de 512 bytes. El uso de BufferedOutputStream es justificado

únicamente cuando el tamaño del buffer a utilizar es mucho mas grande que512 bytes (en este ejemplo 2048). Mientras que ZipOutputSream no te permite

modificar el tamaño del buffer , GZIPOutputStream si lo hace; puedes

especificar el tamaño del buffer interno como un argumento de su constructor.

En este segmento de código, un flujo de salida de archivo se crea usando el nombre de la(s)entrada(s) ZIP que puede recuperarse usando el método entry.getName. La fuente de datos

ZIP es entonces leida y se escribe en un flujo descomprimido:

while ((count = zin.read(data, 0, BUFFER)) != -1) {

//System.out.write(x);

dest.write(data, 0, count);

}

y finalmente, cerramos los flujos de entrada y salida:

dest.flush();dest.close();

zin.close();

El codigo del Ejemplo 1 muestra como descomprimir y extraer archivos desde un archivo

ZIP. Para probar este ejemplo, compila y ejecuta el ejemplo pasándole como parámetro un

archivo comprimido con el formato ZIP:

 prompt> java UnZip somefile.zip 

Nota que somefile.zip debe ser un archivo creado usando alguna herramienta compatible

con el formato ZIP, como WINZIP.

Ejemplo 1: UnZip.java

import java.io.*;

import java.util.zip.*;

public class UnZip {

static final int BUFFER = 2048;

public static void main (String argv[]) {

try {

BufferedOutputStream dest = null;

FileInputStream fis = new

FileInputStream(argv[0]);ZipInputStream zis = new

ZipInputStream(new BufferedInputStream(fis));

ZipEntry entry;

Page 6: comprimir

5/9/2018 comprimir - slidepdf.com

http://slidepdf.com/reader/full/comprimir 6/15

 

http://www.javahispano.com

6

while((entry = zis.getNextEntry()) != null) {

System.out.println("Extracting: " +entry);

int count;

byte data[] = new byte[BUFFER];

// Escribir los archivos en el disco

FileOutputStream fos = new

FileOutputStream(entry.getName());dest = new

BufferedOutputStream(fos, BUFFER);

while ((count = zis.read(data, 0, BUFFER))

!= -1) {

dest.write(data, 0, count);

}

dest.flush();

dest.close();

}

zis.close();

} catch(Exception e) {

e.printStackTrace();

}

}

}

Es importante hacer notar que la clase ZipInputStream lee archivos ZIP secuencialmente. La

clase ZipFile, en cambio, lee el contenido de un archivo ZIP usando un acceso aleatorio

interno para que las entradas del archivo ZIP no tengan que ser leídas secuencialmente

Nota: Otra diferencia fundamental entre ZipInputSream y ZipFile és enterminos del uso de la memoria de intercambio(chaché ). Las entradas ZIP no

son puestas en la memoria de intercambio cuando el archivo es leido usando

una combinación de ZipInputStream y FileInputStream. Por otro lado, si elarchivo es abierto usando ZipFile(fileName) entonces es colocado en la

memoria intermedia, así si ZipFile(fileName) es llamado otra vez el archivo

sólo se abre una vez. Si trabajas sobre UNIX, cabe mencionar que todos los

archivos ZIP abiertos usando ZipFile son abiertos utilizando memoria

mapeada, y por consiguiente el desempeño de ZipFile es superior a

ZipInputStream. Por otro lado, si los contenidos del mismo ZIP, son

frecuentemente modificados y recargados durante la ejecución del programaentonces se recomienda el uso de ZipInputStream 

A continuacion se muestra como se puede descomprimir un archivo ZIP utilizando la clase

ZipFile:

1. Crear un objeto ZipFile especificando el archivo ZIP 

a ser leido, ya sea como un String o como un objeto File:

ZipFile zipfile = new ZipFile("figs.zip");

Page 7: comprimir

5/9/2018 comprimir - slidepdf.com

http://slidepdf.com/reader/full/comprimir 7/15

 

Compresión y descompresión de datos utilizando Java

7

2. Usa el método entries, que retorna un objeto Enumeration, después con un cicloobten todos los objetos ZipEntry del archivo a descomprimir:

3. while(e.hasMoreElements()) {

4. entry = (ZipEntry) e.nextElement();

5. // lee el contenido y guardalo

6. }

7. Lee el contenido de un objeto ZipEntry en especifico dentro del archivo ZIP pasando

el objeto ZipEntry al método getInputStream, que retornará un objeto InputStream desde el cual puedes leer el contenido de las entradas:

8. is = new

9. BufferedInputStream(zipfile.getInputStream(entry));

10. Recupera el nombre de la entrada y crea un flujo de salida para guardarlo:11. byte data[] = new byte[BUFFER];

12. FileOutputStream fos = new

13. FileOutputStream(entry.getName());

14. dest = new BufferedOutputStream(fos, BUFFER);

15. while ((count = is.read(data, 0, BUFFER)) != -1){

16. dest.write(data, 0, count);

17. }

18. Finalmente, cierra todos los fujos de entrada y salida:19. dest.flush();

20. dest.close();

21. is.close();

El código completo de este programa se muestra en el ejemplo 2. Nuevamente, para probaresta clase, compilalo y ejecutalo pasandole como argumento un archivo con formato ZIP: 

 prompt> java UnZip2 somefile.zip 

Ejemplo 2: UnZip2.java

import java.io.*;

import java.util.*;

import java.util.zip.*;

public class UnZip2 {

static final int BUFFER = 2048;public static void main (String argv[]) {

try {

BufferedOutputStream dest = null;

BufferedInputStream is = null;

ZipEntry entry;

ZipFile zipfile = new ZipFile(argv[0]);

Enumeration e = zipfile.entries();

while(e.hasMoreElements()) {

entry = (ZipEntry) e.nextElement();

System.out.println("Extracting: " +entry);

is = new BufferedInputStream

(zipfile.getInputStream(entry));

int count;byte data[] = new byte[BUFFER];

FileOutputStream fos = new

FileOutputStream(entry.getName());

Page 8: comprimir

5/9/2018 comprimir - slidepdf.com

http://slidepdf.com/reader/full/comprimir 8/15

 

http://www.javahispano.com

8

dest = new

BufferedOutputStream(fos, BUFFER);

while ((count = is.read(data, 0, BUFFER))

!= -1) {

dest.write(data, 0, count);

}

dest.flush();dest.close();

is.close();

}

} catch(Exception e) {

e.printStackTrace();

}

}

}

Comprimiendo y Archivando Datos en un Archivo ZIP

la clase ZipOutputStream se usa para compimir datos a un archivo ZIP. ZipOutputStream 

escribe datos, en un flujo de salida, en un archivo con formato ZIP. La creación de un archivo

ZIP involucra la siguiente serie de pasos:

1. El primer paso es crear un objeto ZipOutputStream ; le pasaremos como parámetro el

flujo de salida del archivo al cual queremos escribir. Aqui se muestra la manera decrear un archivo ZIP llamado "myfigs.zip":

2. FileOutputStream dest = new

3. FileOutputStream("myfigs.zip");

4. ZipOutputStream out = new

5. ZipOutputStream(new

BufferedOutputStream(dest));

6. Una vez que el flujo de salida objetivo es creado, el siguiente paso es abrir el o losarchivos origen de los datos. En este ejemplo, los archivos a partir de los cuales secreará el archivo ZIP son aquellos archivos que se escuentren en el directorio actual.

El método list se usa en este ejemplo para obtener la lista de los archivos que se

encuentran en el directorio actual:7. File f = new File(".");

8. String files[] = f.list();

9. for (int i=0; i<files.length; i++) {

10. System.out.println("Adding: "+files[i]);

11. FileInputStream fi = new FileInputStream(files[i]);

12. // creamos una entrada zip

13. // agregamos entradas zip al archivo

14. }

Nota:El código anterior es capaz de comprimir todos los archivos que se encuentranen el directorio actual. No maneja subdirectorios. Como ejercicio, puedes intentar

modificar el ejemplo 3 para que maneje subdirectorios

Page 9: comprimir

5/9/2018 comprimir - slidepdf.com

http://slidepdf.com/reader/full/comprimir 9/15

 

Compresión y descompresión de datos utilizando Java

9

15. Creamos un ZipEntry por cada archivo leido:16. ZipEntry entry= new ZipEntry(files[i])

17. Antes de escribir los datos en el flujo ZIP de salida, debes primero colocarle el objeto

ZipEntry usando el método putNextEntry:18. out.putNextEntry(entry);

19. Escribimos los datos en el archivo ZIP:20. int count;

21. while((count = origin.read(data, 0, BUFFER)) != -1) {

22. out.write(data, 0, count);

23. }

24. Finalmente, cerramos los flujos de entrada y salida:25. origin.close();

26. out.close();

El código completo de todo lo anterior se muestra en el ejemplo 3.

Ejemplo 3: Zip.java

import java.io.*;

import java.util.zip.*;

public class Zip{

static final int BUFFER = 2048;

public static void main(String argv[]){

try{

BufferedInputSream origin = null;

FileOutputStream dest = new

FileOutputStream("c:\\temp\\myfigs.zip");

ZipOutputStream out = new ZipOutputStream( newBufferedOutputStream(dest));

//out.setMethod(ZipOutputStream.DEFLATED);

byte data[] = new byte[BUFFER];

//obtenemos la lista de los archivos del directorio actual

File f = File(".");

String files[] = f.list();

for (int i=0; i>files.length; ++i){

System.out.println("Adding: "+file[i]);

FileInputStream fi = new

FileInputStream(files[i]);

origin = new

BufferedInputSteam(fi, BUFFER);

ZipEntry entry = new ZipEntry(files[i]);out.putNextEntry(entry);

int count;

while((count = origin.read(data, 0,

BUFFER))!= -1){

out.write(data, 0, count);

}

origin.close();

}

out.close();

}catch(Exception e){

e.printStrackTrace();

}

}}

Page 10: comprimir

5/9/2018 comprimir - slidepdf.com

http://slidepdf.com/reader/full/comprimir 10/15

 

http://www.javahispano.com

10

Nota:Las entradas pueden ser agregadas al archivo ZIP de forma comprimida(DEFLATED) o no comprimida(STORED). El método setMethod se usa para

fijar el método de almacenamiento. Por ejemplo, para fijar el método a

DEFLATED (comprimido) es:out.setMethod(ZipOutputStream.DEFLATED) y para fijarlo a STORED (no

comprimido) es: out.setMethod(ZipOutputStream.DEFLATED)  

Propiedades de un Archivo ZIP

La clase ZipEntry describe un archivo comprimido almacenado en un archivo ZIP . Los

distintos métodos contenidos en esta clase se usan para fijar u obtener fragmentos de

información acerca de la entrada actual. la clase ZipEntry se usa con las clases ZipFile yZipInputStream para leer archivos ZIP. Algunos de los métodos mas utilizados disponibles

en la clase ZipEntry son los que se muestran junto con una descripcion en la tabla 2.

Tabla 2. Algunos métodos utiles de la clase ZipEntry

Método Descripcion

public String getComment()  Retorna un comentario sobre la entrada, null si notiene comentario 

public long

getCompressedSize()  Retorna el tamaño comprimido de la entrada, -1 si se

desconoce

public int getMethod() Retorna el método de compresión de la entrada, -1 si no

esta especificadopublic String getName()  Retorna el nombre de la entrada

public long getSize() Retorna el tamaño sin comprimir de la entrada, -1 si se

desconoce

public long getTime() Retorna la fecha de modificacion de la entrada, -1 si no

esta especificado

public void setComment(String

c)  Fija un comentario opcional para la entrada

public void setMethod(int

method)  Fija el método de compresion para la entrada

public void setSize(longsize)  Fija el tamaño sin comprimir de la entrada

public void setTime(long

time)  Fija la fecha de modificacion de la entrada

Suma de Comprobación (Checksum) 

Algunas otras clases importantes del paquete java.util.zip son Adler32 y CRC32, estas

clases implementan la interface java.util.zip.Checksum y calculan la suma de

comprobación requerida para la compresión de datos. El algoritmo Adler32 se conoce por ser

mas rápido que el CRC32, y éste ultimo es conocido por ser más confiable.

Page 11: comprimir

5/9/2018 comprimir - slidepdf.com

http://slidepdf.com/reader/full/comprimir 11/15

 

Compresión y descompresión de datos utilizando Java

11

las sumas de comprobación se usan para detectar archivos o mensajes corruptos. Por ejemplo,imagina que quieres crear un archivo ZIP y después transferirlo a una PC remota. Una vez

que está en la máquina remota, usando la suma de comprobacion, puedes verificar si elarchivo se corrompió durante la transmisión. Para mostrar como crear una suma de

verificacion, hemos modificado el ejemplo 1 y el ejemplo 3, para usar CheckedInputStream y

CheckedOutputStream, ésto se muestra en los ejemplos 4 y 5.

Ejemplo 4: Zip.java

import java.io.*;

import java.util.zip.*;

public class Zip {

static final int BUFFER = 2048;

public static void main (String argv[]) {

try {

BufferedInputStream origin = null;

FileOutputStream dest = new

FileOutputStream("c:\\temp\\myfigs.zip");

CheckedOutputStream checksum = new

CheckedOutputStream(dest, new Adler32());

ZipOutputStream out = new

ZipOutputStream(new

BufferedOutputStream(checksum)); 

//out.setMethod(ZipOutputStream.DEFLATED);

byte data[] = new byte[BUFFER];

// get a list of files from current directory

File f = new File(".");

String files[] = f.list();

for (int i=0; i<files.length; i++) {

System.out.println("Adding: "+files[i]);

FileInputStream fi = new

FileInputStream(files[i]);

origin = new

BufferedInputStream(fi, BUFFER);

ZipEntry entry = new ZipEntry(files[i]);

out.putNextEntry(entry);

int count;

while((count = origin.read(data, 0,

BUFFER)) != -1) {

out.write(data, 0, count);

}

origin.close();

}

out.close();

System.out.println("checksum:

"+checksum.getChecksum().getValue());  

} catch(Exception e) {

e.printStackTrace();

}

}

}

Ejemplo 5: UnZip.java

import java.io.*;import java.util.zip.*;

public class UnZip {

Page 12: comprimir

5/9/2018 comprimir - slidepdf.com

http://slidepdf.com/reader/full/comprimir 12/15

 

http://www.javahispano.com

12

public static void main (String argv[]) {

try {

final int BUFFER = 2048;

BufferedOutputStream dest = null;

FileInputStream fis = new

FileInputStream("c:\\temp\\myfigs.zip");

CheckedInputStream checksum = newCheckedInputStream(fis, new Adler32());

ZipInputStream zis = new

ZipInputStream(new

BufferedInputStream(checksum)); 

ZipEntry entry;

while((entry = zis.getNextEntry()) != null) {

System.out.println("Extracting: " +entry);

int count;

byte data[] = new byte[BUFFER];

// write the files to the disk

FileOutputStream fos = new

FileOutputStream(entry.getName());

dest = new BufferedOutputStream(fos,

BUFFER);

while ((count = zis.read(data, 0,

BUFFER)) != -1) {

dest.write(data, 0, count);

}

dest.flush();

dest.close();

}

zis.close();

System.out.println("Checksum:

"+checksum.getChecksum().getValue());  

} catch(Exception e) {

e.printStackTrace();

}

}

}

Para probar los ejemplos 4 y 5, compila las clases y ejecuta primero la clase Zip para crear un

archivo ZIP (se calculará el valor de la suma de comprobación y se mostrará en la pantalla ),

después ejecuta la clase UnZip para descomprimir el archivo (nuevamente el valor de la suma

de comprobación se mostrará en la pantalla). Los dos valores deben ser exactamente iguales,de no ser así, el archivo esta corrupto. Las sumas de verificacion son muy útiles para validar

datos. Por ejemplo, puedes crear un archivo ZIP y enviarselo a un amigo junto con el valor de

la suma de comprobación. Tu amigo descomprime el archivo y compara el valor de la suma

de comprobación, si los dos valores son iguales, tu amigo sabe que el archivo es auténtico.

Comprimiendo de Objetos

Hemos visto cómo comprimir datos que se encuentran en forma de archivos y agregarlos a un

archivo apropiado. ¿Pero qué sucede si los datos que deseamos comprimir no están disponibleen un archivo? Asumamos por ejemplo, que estas transfiriendo objetos grandes a través de

sockets. Para mejorar el desempeño de tu aplicación, puedes querer comprimir los objetosantes de enviarlos por la red y descomprimirlos cuando lleguen a su destino. Como otroejemplo, digamos quieres guardar objetos en el disco en un formato comprimido. El formato

ZIP que esta basado en registros, no es muy conveniente para este trabajo. El formato GZIP esmás apropiado ya que funciona como un sencillo flujo de datos.

Page 13: comprimir

5/9/2018 comprimir - slidepdf.com

http://slidepdf.com/reader/full/comprimir 13/15

 

Compresión y descompresión de datos utilizando Java

13

Ahora, veamos un ejemplo de cómo comprimir objetos antes de escribirlos en el disco y cómodescomprimirlos después de leerlos del disco. El ejemplo 6 es una sencilla clase queimplementa la interface Serializable para indicarle a la JVM que deseamos serializar

instancias de esta clase.

Ejemplo 6: Employee.java

import java.io.*;

public class Employee implements Serializable {

String name;

int age;

int salary;

public Employee(String name, int age, int salary) {

this.name = name;

this.age = age;

this.salary = salary;

}

public void print() {

System.out.println("Record for: "+name);

System.out.println("Name: "+name);

System.out.println("Age: "+age);

System.out.println("Salary: "+salary);

}

}

Ahora, escribamos otra clase que cree un par de objetos de la clase Employee. El ejemplo 7

crea dos objetos (sarah y sam) de la clase Employee, despues guarda su estado en un archivo

con un formato comprimido.

Ejemplo 7 SaveEmployee.java

import java.io.*;

import java.util.zip.*;

public class SaveEmployee {

public static void main(String argv[]) throws

Exception {

// creamos algunos objetos

Employee sarah = new Employee("S. Jordan", 28,

56000);

Employee sam = new Employee("S. McDonald", 29,

58000);

// Serializamos los objetos sarah y sam

FileOutputStream fos = new

FileOutputStream("db");

GZIPOutputStream gz = new GZIPOutputStream(fos);

ObjectOutputStream oos = new

ObjectOutputStream(gz);

oos.writeObject(sarah);

oos.writeObject(sam);

oos.flush();

oos.close();

fos.close();

}

}

Ahora, la clase ReadEmployee mostrada en el ejemplo 8, se usa para reconstruir el estado de

los dos objetos. Una vez que el estado se ha reconstruido, el método print se invoca en ellos.

Page 14: comprimir

5/9/2018 comprimir - slidepdf.com

http://slidepdf.com/reader/full/comprimir 14/15

 

http://www.javahispano.com

14

Ejemplo 8: ReadEmployee.java

import java.io.*;

import java.util.zip.*;

public class ReadEmployee {

public static void main(String argv[]) throwsException{

//des-serializamos los objetos sarah y sam

FileInputStream fis = new FileInputStream("db");

GZIPInputStream gs = new GZIPInputStream(fis);

ObjectInputStream ois = new ObjectInputStream(gs);

Employee sarah = (Employee) ois.readObject();

Employee sam = (Employee) ois.readObject();

//mostramos los datos despues de reconstruir el estado de los

objetos

sarah.print();

sam.print();

ois.close();

fis.close();}

}

La misma idea se puede usar para comprimir grandes objetos que son enviados a través desockets. El siguiente fragmento de código muestra como escribir objetos en un formatocomprimido, desde el lado del servidor para el cliente:

// escribir para el cliente

GZIPOutputStream gzipout = new

GZIPOutputStream(socket.getOutputStream());

ObjectOutputStream oos = new

ObjectOutputStream(gzipout);

oos.writeObject(obj);

gzipos.finish();

Y, el siguiente fragmento de código muestra como descomprimir estos objetos del lado delcliente una vez recibidos desde el servidor:

// leer desde el servidor

Socket socket = new Socket(remoteServerIP, PORT);

GZIPInputStream gzipin = new

GZIPInputStream(socket.getInputStream());

ObjectInputStream ois = new ObjectInputStream(gzipin);

Object o = ois.readObject();

¿Y los archivos JAR?

El formato JAR(Java ARchive) esta basado en el formato normal ZIP con un archivo

manifiesto opcional. Si deseas crear archivos JAR o extraer archivos desde una archivo JAR

desde tus aplicaciones Java, usa el paquete java.util.jar, que proporciona clases para leer

y escribir archivos JAR. El uso de las clases proporcionadas por el paquete java.util.jar es bastante similar al uso de las clases del paquete java.util.zip descritas en este artículo.

Por consiguiente, podras adaptar mucho del código de este artículo si deseas usar el paquete

java.util.jar .

Conclusión

Este artículo planteó las APIs que puedes usar para comprimir y descomprimir datos desde tus

aplicaciones, con ejemplos a lo largo del artículo se mostró cómo usar el paquete

Page 15: comprimir

5/9/2018 comprimir - slidepdf.com

http://slidepdf.com/reader/full/comprimir 15/15

 

Compresión y descompresión de datos utilizando Java

15

java.util.zip para comprimir y descomprimir datos. Ahora tienes las herramientasnecesarias para comprimir y descomprimir datos desde tus aplicaciones Java.

El artículo también muestra cómo comprimir y descomprimir datos al vuelo para reducir eltráfico de la red y mejorar el desempeño de tus aplicaciones cliente/servidor. La compresion

de datos al vuelo , sin embargo, sólo mejora el desempeño de aplicaciones cliente/servidorcuando los objetos que están siendo comprimidos tiene un par de cientos de bytes comotamaño. No podras observar ésta mejoría si los objetos que se están comprimiendo y

transfiriendo son sencillos objetos String, por ejemplo.

Para más información

• El paquete java.util.zip 

• El paquete java.util.jar • Serialización de Objetos • Transportanto objetos sobre Sockets 

Descarga el código utilizado en este artículo. 

 

Isaac Ruíz, RuGI , egresado del ITI (Istmo de Tehuantepec, Oaxaca, Mexico) en la Carrerade Ingeniería en Sistemas Computacionales, es actualmente desarrollador independiente Javacon intenciones de realizar el examen de certificación

Cuando no esta programando o navegando (¿?) le gusta mucho leer todo aquello que le de elmas pequeño indicio de como llegar al Valhala o por lo menos a Avalon =:D

Para cualquier duda o comentario: [email protected]