En el mundo de la transmisión de datos la eficiencia con la cual transmitimos información es muy importante. Por eso se han inventado los algoritmos de compresión de datos; para reducir el tamaño de estos datos partiendo de un algoritmo matemático que puede comprimir y descomprimir la información.

Para entender cómo funciona la compresión de datos podemos observar un ejemplo simple de redundancia de datos en un archivo. Digamos que tenemos la siguiente cadena:

AAAAIIEEYYYYLLLLXXAAAA

Vemos que las letras se repiten seguido, entonces para comprimir esa cadena agrupamos los caracteres en una notación más conveniente:

4A2I2E4Y4L2X4A

Donde “4A” significa que hay 4 caracteres “A” seguidos. A partir de esto se han desarrollado muchísimos algoritmos que buscan escribir datos extensos de una forma representativa para comprimirlos. O en el caso de archivos multimedia suprimir información imperceptible a nuestros sentidos para hacer más ligeros los archivos.

En el lenguaje java, tenemos la opción de comprimir nativamente usando el API de compresión java.util.zip 

El caso de uso clásico para esto es en el que comprimimos un archivo usando el algoritmo zip. Digamos que tenemos un archivo prueba.doc y lo queremos comprimir.  Lo primero que tenemos que hacer es convertir el archivo a un arreglo de bytes. Para eso hay 2 opciones:

1. usando apache commons FileUtils (forma fácil)

import org.apache.commons.io.FileUtils;

...

String archivo = "prueba.doc"
byte[] data = FileUtils.readFileToByteArray(archivo);

2. Utilizando clases solo de java nativo

    public static byte[] getBytesFromFile(File file) throws IOException {        
        long length = file.length();

        if (length > Integer.MAX_VALUE) {
            throw new IOException("El archivo es kilometrico!!! Intente uno mas chico.");
        }

        byte[] bytes = new byte[(int)length];
        int offset = 0;
        int numRead = 0;

        InputStream is = new FileInputStream(file);
        try {
            while (offset < bytes.length
                   && (numRead=is.read(bytes, offset, bytes.length-offset)) >= 0) {
                offset += numRead;
            }
        } finally {
            is.close();
        }

        if (offset < bytes.length) {
            throw new IOException("No se pudo leer el archivo en su totalidad "+file.getName());
        }
        return bytes;
    }

Cuando ya tenemos el array de datos, podemos comprimirlos utilizando

java.util.zip.Deflater

Aquí un bonito ejemplo de como usar el Deflater:

public static byte[] compress(byte[] data) throws IOException {
   Deflater deflater = new Deflater();  
   deflater.setInput(data);  
   ByteArrayOutputStream outputStream = new ByteArrayOutputStream(data.length);   
   deflater.finish();  
   byte[] buffer = new byte[1024];   
   while (!deflater.finished()) {  
    int count = deflater.deflate(buffer); 
    outputStream.write(buffer, 0, count);   
   }  
   outputStream.close();  
   byte[] output = outputStream.toByteArray();  
   LOG.debug("Original: " + data.length / 1024 + " Kb");  
   LOG.debug("Comprimido: " + output.length / 1024 + " Kb");  
   return output;  
  }

Ahora de manera similar para descomprimir información, usamos:

java.util.zip.Inflater

Y con un ejemplo igual que antes, solo que esta vez en lugar de comprimir; descomprimimos.

  public static byte[] decompress(byte[] data) throws IOException, DataFormatException {  
   Inflater inflater = new Inflater();   
   inflater.setInput(data);  
   ByteArrayOutputStream outputStream = new ByteArrayOutputStream(data.length);  
   byte[] buffer = new byte[1024];  
   while (!inflater.finished()) {  
    int count = inflater.inflate(buffer);  
    outputStream.write(buffer, 0, count);  
   }  
   outputStream.close();  
   byte[] output = outputStream.toByteArray();  
   LOG.debug("Original: " + data.length);  
   LOG.debug("Compressed: " + output.length);  
   return output;  
  }

De esa manera podemos comprimir y descomprimir archivos, o streams fácilmente utilizando java.

Categorized in: