Descompresion de ficheros ZIP.

El tamaño de los ficheros para su almacenamiento y envió por la red es significativo. Son muchos los formatos usados para guardar de información de forma comprimida.

Se puede distinguir dos tipos de compresión de datos:

  • Los que tienen perdidas usados en campos donde una reducción de la información no es significativa: gráficos, sonido, etc.
  • Los que no tienen perdidas usados en campos donde la totalidad de la información debe ser recuperada.

El JDK proporciona un soporte excelente para el tratamiento de ficheros ZIP.

Para la implementación de las clases que dan soporte al formato ZIP, Java utiliza como base una librería en código nativo basada en la ZLib.

Las clases para el tratamiento de los ficheros en formato ZIP contemplan el uso de ficheros comprimidos con el método deflate/inflate y ficheros no comprimidos(simplemente almacenados).

El algoritmo deflate es el que permite la compresión de ficheros y está implementado en la clase deflate y la descompresión corre a cargo de la clase inflate.

La librería ZLIB fue desarrollada inicialmente como parte de los gráficos PNG. La descripción del formato deflate se puede encontrar en la RFC 1951.

Las clases que intervienen en la compresión/descompresión de ficheros son varias aunque sólo tres de ellas nos interesan:

  • ZipFile
  • ZipEntry
  • ZipException

La clase ZipFile se usa para abrir el fichero Zip y es por tanto el punto de partida para la extracción de ficheros.

Esta clase nos proporciona una enumeración de todas las entradas de los ficheros que están almacenados en el ZIP por medio del método entries(). Los objetos que devuelve la enumeración son objetos de la clase ZipEntry. También es posible obtener los datos concernientes a un fichero en concreto de forma directa si conocemos el nombre con el que está almacenado el fichero.. Dados estos métodos podemos buscan una entrada (ZipEntry) asociada a un nombre de fichero comprimido de forma directa, o recorrerlas todas las entradas de forma secuencial.

El descompresor

Para demostrar el uso de las clases crearemos un pequeño ejemplo consistente en una aplicación capaz de extraer los ficheros contenidos en un archivo ZIP.

El programa consta de 4 clases:

  • jZipException: la excepción generada por la aplicación.
  • jUnzip: clase que contiene los métodos para la extracción de ficheros.
  • toolsZip: contienen los métodos de creación de directorios y nombres de los ficheros.
  • javaUnzip: es la clase que contiene el main.
jZipException

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

public class jZipException extends Exception {
   public jZipException(String strError) {
      super(strError);
   }
}

La clase jZiException únicamente implementa el constructor al que se le pasa la cadena con el mensaje de error.

jUnzip

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

public class jUnzip {

   static public boolean decompressFile(String fileName, String dirBase) 
       throws jZipException{
      ZipFile zf= null;
      byte buffer[] = new byte[4048];/* tamaño del buffer de descompresión*/
      int lenToWrite;
      boolean flagDirBase;
      String separator = "";
      if (dirBase == null) {
         flagDirBase = false;
         dirBase = "";
      }else {
           flagDirBase = true;
           if(!dirBase.endsWith(File.separator) && dirBase.length()>0) {
              separator = File.separator;
           }
      }
      try {
         zf = new ZipFile(fileName);
         Enumeration e = zf.entries();
         for (;e.hasMoreElements();) {
            ZipEntry z = (ZipEntry)e.nextElement();
            System.out.println(z.getName() + " -> " + dirBase + separator + 
                  toolsZip.getRealNameFile(z.getName(), flagDirBase));
            InputStream in = zf.getInputStream(z);
            if(flagDirBase)
               toolsZip.createDirFromNameFile(dirBase, z.getName());
            FileOutputStream fTarget = new FileOutputStream(dirBase + 
              separator + toolsZip.getRealNameFile(z.getName(), flagDirBase));
            while ((lenToWrite=in.read(buffer)) != -1) {
                      fTarget.write(buffer,0,lenToWrite);
             }
             fTarget.close();
         }
      }
      catch(IOException e) {
         System.out.println("[decompressFile] Exception " + e.getMessage());
         throw  new jZipException("[decompressFile]"+ e.getMessage());
      }
      finally{
         try {
            if ( zf != null) {
               zf.close();
            }
      }
      catch(IOException ee) {
         System.out.println("[decompressFile] Exception in close file:" 
            + ee.getMessage());
         throw  new jZipException("[decompressFile]"+ ee.getMessage());
      }
   }
   return true;
   }
}

La clase jUnzip es la que lleva el peso de la descompresión con el método decompressFile. Este método tiene dos parámetros:

  • String fileName: es el nombre del fichero ZIP.
  • String dirBase: es el path base en el que se descomprime los archivos.

La instancia de la clase ZipFile nos proporciona las entradas de los archivos que contiene y añade a los nombres de cada uno de los archivos comprimidos el directorio base: dirBase. Si no especificamos ningún directorio por defecto los descomprime en el que se ejecuta la aplicación.

En el caso de que haya algún problema se lanzará una excepción de tipo jZipException.

toolsZip

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

public class toolsZip {
   static public boolean mkdir(String namePath) throws jZipException{
      File file = new File(namePath);
      boolean ret = false;
      try {
         if (file.exists()) {
            if (file.isDirectory())
               return true;
            else
               return false;
         }   else
            ret = file.mkdirs();
     }
     catch(SecurityException ee) {
         String str = "[mkdir] " + ee.getMessage();
         System.err.println(str);
         throw new jZipException(str);   
      };
      return ret;
   }
/************************************************************************/   
   static public boolean createDirFromNameFile(String dirBase, String pathfile) {
      String path; 
      String file; 
      int lenpath;
      int lenfile;
   
   //path complero sustiltuyendo caracteres no adecuados

      path = getRealFileName(pathfile, true);    
      file = getRealFileName(pathfile, false);
      lenpath = path.length();
      lenfile = file.length();
      if(lenpath  == lenfile && dirBase.length()==0)
         return true;
      file = path.substring(0, lenpath-lenfile);
      if(file.endsWith(File.separator)) {
         path = file.substring(0, lenpath-lenfile-1);
      }
      else
         path = file;
      try {   
         if(!mkdir(dirBase + path))
            return false;
      }
      catch(Exception e) {
         System.err.println("[mkdir]Exception " + e.getMessage());   
         return false;
      }
      return true;
   }   
/****************************************************************************/
   static public String getRealFileName(String file, boolean full) {
         String ret = file;
         String aux = file.replace('/', File.separator.charAt(0));
         if(full)
            ret = aux; 
         else {   
         StringTokenizer st = new StringTokenizer(aux, File.separator.charAt);
            while(st.hasMoreTokens()) {
                ret = st.nextToken();
             }
         }   
         return ret;
   }
}

La clase toolsZip contiene todos los métodos que son de utilidad para la manipulación de ficheros y directorios:

  • mkdir crea un directorio con el nombre especificado por el parámetro namePath.
  • getRealFileName tiene una doble utilidad: por un lado coge el el nombre del fichero file y traduce las barra de los directorios a las propias de la plataforma de ejecución y si full es false sólo retorna el nombre del fichero, si es true retorna todo el path.
  • createDirFromNameFile crea el directorio donde se debe grabar el fichero teniendo en cuenta el directorio base y el nombre del directorio de la aplicación.
javaUnzip

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

public class javaUnzip {
   public static void main(String args[]) {
      String path = "";
      String file = "";
      if (args.length < 2 ){
         System.out.println("sintaxis: " +
            "javaUnzip  <nombre fichero> <directorio_descompresión>");
         return;
      }
      file = args[0];
      path = args[1];
      try {
               jUnzip.decompressFile(file, path);
      }
      catch(Exception e ) {
         System.out.println("ERROR:" + e.getMessage());
      }
   }
}

javaUnzip contiene el código que obtiene los parámetros y llama a jUnzip.descompresFile

Bibliografía y referencias

COMPARTE ESTE ARTÍCULO

ENVIAR A UN AMIGO
COMPARTIR EN FACEBOOK
COMPARTIR EN TWITTER
COMPARTIR EN GOOGLE +
¡SÉ EL PRIMERO EN COMENTAR!
Conéctate o Regístrate para dejar tu comentario.