Buscar
Social
Ofertas laborales ES
« Emulador de GBA en Java | Main | Jext actualizado »
lunes
abr012002

Compresrión en Java

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/compression/



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


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



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




0000000000000000000000000000000000000000

0000000000000000000000000000000000000000

0000000000111111111111111111110000000000

0000000000100000000000000000010000000000

0000000000100000000000000000010000000000

0000000000100000000000000000010000000000

0000000000111111111111111111110000000000

0000000000000000000000000000000000000000




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
bits identicos, así:




0, 40

0, 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 tercera línea dice que la tercera línea del mapa de bit's consiste en 10 0's
seguidos por 20 1's y seguidos 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 todos los 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. Para má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, la transferencia 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 o usando dispositivos de hardware especiales que ya
incorporán las técnicas de compresión. La Figura 2 muestra un diagrama de bloques basico
sobre la compresión de datos.

























_________________
---------------------->Compresion---------------------->
Datos OriginalesdeDatos 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 que se utiliza para crear un archivo comprimido y para extraer archivos de un
archivo comprimido. 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 archivos con los formatos ZIP y GZIP. También te proporciona
clases para comprobar las sumas de control 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 la Tabla 1.


Tabla 1. El paquete java.util.zip





























































































ElementoTipoDescripción
ChecksumInterfaceRepresenta un dato de la suma de control (data checksum).
Implementado por las clases Adler32 y CRC32
Adler32ClaseUsado para calcular la suma de control(checksum) de un flujo de
datos
CheckedInputStreamClaseUn flujo de entrada que guarda la suma de control de los datos que estan
siendo leídos.
CheckedOutputStreamClaseUn flujo de salida que guarda la suma de control de los datos que estan
siendo escritos.
CRC32ClaseUsado para calcular la suma de control CRC32 de un flujo de
datos
DeflaterClaseSoporte para compresion usando la librería ZLIB
DeflaterOutputStreamClaseUn flujo de salida filtrado para la compresión de datos con el formato de
compresión deflate
GZIPInputStreamClaseUn flujo de entrada filtrado para leer datos comprimidos con el formtato
GZIP
GZIPOutputStreamClaseUn flujo de salida filtrado para escribir datos comprimidos con el formato
GZIP
InflaterClaseSoporte para descompresion usando la librería ZLIB
InflaterInputStreamClaseUn flujo de entrada filtrado para la descompresion de datos con el formato de
compresión deflate
ZipEntryClaseRepresenta la entrada de un archivo ZIP
ZipFileClaseUsado para leer entradas de un archivo ZIP
ZipInputStreamClaseUn filtro de entrada para leer archivos con el formato ZIP
ZipOutputStreamClaseUn filtro de salida para escribir archivos con el formato
ZIP
DataFormatExceptionClase de excepcionLanza una excepción para señalar un error en el formato de los datos
ZipExceptionClase de exepcionLanza 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 por
patentes.




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 siguiente fragmento 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 el mé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 la siguiente manera:

int BUFFER = 2048;
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 que 512 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;
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 en terminos 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 el archivo 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 programa entonces 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
  2. a ser leido, ya sea como un String o como un objeto File:

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

  3. Usa el método entries, que retorna un objeto Enumeration, después con un ciclo obten todos los objetos ZipEntry del archivo a descomprimir:
    while(e.hasMoreElements()) {
    entry = (ZipEntry) e.nextElement();
    // lee el contenido y guardalo
    }

  4. 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:
    is = new
    BufferedInputStream(zipfile.getInputStream(entry));


  5. Recupera el nombre de la entrada y crea un flujo de salida para guardarlo:

    byte data[] = new byte[BUFFER];
    FileOutputStream fos = new
    FileOutputStream(entry.getName());
    dest = new BufferedOutputStream(fos, BUFFER);
    while ((count = is.read(data, 0, BUFFER)) != -1){
    dest.write(data, 0, count);
    }


  6. Finalmente, cierra todos los fujos de entrada y salida:

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



El código completo de este programa se muestra en el ejemplo 2. Nuevamente, para probar esta 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());
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 de crear un archivo ZIP llamado "myfigs.zip":

    FileOutputStream dest = new
    FileOutputStream("myfigs.zip");
    ZipOutputStream out = new
    ZipOutputStream(new BufferedOutputStream(dest));

  2. Una vez que el flujo de salida objetivo es creado, el siguiente paso es abrir el o los archivos origen de los datos. En este ejemplo, los archivos a partir de los cuales se creará 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:


    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]);
    // creamos una entrada zip
    // agregamos entradas zip al archivo
    }




    Nota:El código anterior es capaz de comprimir todos los archivos que se encuentran
    en el directorio actual. No maneja subdirectorios. Como ejercicio, puedes
    intentar modificar el ejemplo 3 para que maneje subdirectorios




  3. Creamos un ZipEntry por cada archivo leido:

    ZipEntry entry= new ZipEntry(files[i])


  4. Antes de escribir los datos en el flujo ZIP de salida, debes primero colocarle el objeto ZipEntry usando el método putNextEntry:

    out.putNextEntry(entry);

  5. Escribimos los datos en el archivo ZIP:

    int count;
    while((count = origin.read(data, 0, BUFFER)) != -1) {
    out.write(data, 0, count);
    }


  6. Finalmente, cerramos los flujos de entrada y salida:

    origin.close();
    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( new
BufferedOutputStream(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();
}
}
}




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 y ZipInputStream 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étodoDescripcion
public String getComment()Retorna un comentario sobre la entrada, null si no tiene 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 especificado
public 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(long size)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.



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 el archivo 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 {
public static void main (String argv[]) {
try {
final int BUFFER = 2048;
BufferedOutputStream dest = null;
FileInputStream fis = new
FileInputStream("c:\\temp\\myfigs.zip");
CheckedInputStream checksum = new
CheckedInputStream(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 disponible en 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 objetos antes de enviarlos por la red y descomprimirlos cuando lleguen a su destino. Como otro ejemplo, 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 es más apropiado ya que funciona como un sencillo flujo de datos.


Ahora, veamos un ejemplo de cómo comprimir objetos antes de escribirlos en el disco y cómo descomprimirlos después de leerlos del disco. El ejemplo 6 es una sencilla clase que implementa 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.

Ejemplo 8: ReadEmployee.java



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

public class ReadEmployee {
public static void main(String argv[]) throws
Exception{
//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 de sockets. El siguiente fragmento de código muestra como escribir objetos en un formato comprimido, 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 del cliente 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 java.util.zip para comprimir y descomprimir datos. Ahora tienes las herramientas necesarias 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 el trá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/servidor cuando los objetos que están siendo comprimidos tiene un par de cientos de bytes como tamañ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









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



















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

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


Para cualquier duda o comentario: RuGI_ARROBA_javahispano.com



Reader Comments

There are no comments for this journal entry. To create a new comment, use the form below.
Comentarios deshabilitados
Comentarios deshabilitados en esta noticia.