Páginas

miércoles, 7 de diciembre de 2016

Añadir un fichero nuevo a un fichero zip previamente existente

Hola

Se nos presentó la necesidad de añadir contenido a ciertos ficheros ZIP preexistentes, para abordar el problema podíamos usar la librería Commons Compress de Apache (https://commons.apache.org/proper/commons-compress/) o directamente las clases del paquete 'java.util.zip' del JDK.

El problema es que ambas librerías no añaden contenido a un zip preexistente, sino que sobrescriben el contenido del ZIP original por el nuevo contenido. Debe ser por alguna cuestión 'conceptual' relativa al formato ZIP.

Por tanto la forma de abordar el problema es generar un nuevo fichero zip temopral, volcar en dicho fichero el contenido del fichero zip original, añadir al fichero zip temporal el nuevo fichero, borrar el fichero zip original y renombrar el fichero temporal con el nombre del original.

Ya puestos a documentar el tema, dejo el código con la clase generada:

package org.casa.test;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

public class TestZip {

 private static final int BUFFER_SIZE = 1024;

 /**
  * Crea un fichero zip a partir del fichero recibido con el nombre
  * de dicho fichero y extensión zip, el zip se genera en la carpeta
  * que contiene el fichero recibido.
  * 
  * @param fichero
  * @throws IOException
  */
 public static void comprimeFichero(final File fichero) throws IOException {

  //Generamos un fichero zip con nombre del fichero recibido y extensión zip
  final String nombreFichZip = fichero.getName().substring(0, fichero.getName().lastIndexOf("."))+".zip";

  //Creamos el nuevo fichero zip en la ubicación del fichero recibido
  final File zf = new File(fichero.getParentFile()+File.separator+nombreFichZip);
  final FileOutputStream fos = new FileOutputStream(zf);
  final ZipOutputStream zos = new ZipOutputStream(fos);

  //Comprimimos el fichero recibido en el nuevo zip
  final ZipEntry ze = new ZipEntry(fichero.getName());
  zos.putNextEntry(ze);
  final FileInputStream fisEntry = new FileInputStream(fichero);
  copyToZip(fisEntry, zos);

  //Cerramos los manejadores
  fisEntry.close();
  zos.flush();
  zos.closeEntry();
  zos.close();
  fos.close();
 }

 /**
  * Crea un fichero zip con todos los ficheros contenidos en la carpeta
  * recibida, el zip tendrá el nombre del directorio con extensión zip y 
  * se ubicará en el directorio padre del directorio recibido.
  * 
  * @param directorio
  * @throws IOException 
  */
 public static void comprimeDirectorio(final File carpeta) throws IOException {

  //Generamos un fichero zip con nombre de la carpeta recibida y extensión zip
  final String nombreFichZip = carpeta.getName()+".zip";

  //Creamos el nuevo fichero zip en la carpeta padre de la carpeta recibida
  final File zf = new File(carpeta.getParentFile()+File.separator+nombreFichZip);
  final FileOutputStream fos = new FileOutputStream(zf);
  final ZipOutputStream zos = new ZipOutputStream(fos);

  //Comprimimos cada fichero de la carpeta en el nuevo zip
  ZipEntry ze = null;
  FileInputStream fisEntry = null;
  for (final File fich : carpeta.listFiles()) {
   ze = new ZipEntry(fich.getName());
   zos.putNextEntry(ze);
   fisEntry = new FileInputStream(fich);
   copyToZip(fisEntry, zos);
   fisEntry.close();
  }

  //Cerramos los manejadores
  zos.flush();
  zos.closeEntry();
  zos.close();
  fos.close();
 }

 /**
  * Añade un nuevo fichero comprimido al fichero zip recibido por parámetro.
  * 
  * Creamos un zip temporal intermedio donde copiamos el contenido del zip
  * recibido y en este zip temporal añadimos el fichero recibido. Finalmente
  * reemplazamos el fichero zip original con el fichero zip generado.
  * 
  * @param zipFile
  * @param fichero
  * @throws IOException
  */
 public static void addFicheroZip(final File zipFile, final File fichero) throws IOException {

  //Guardamos el nombre y el path del fichero zip recibido
  final String nombreFicheroZip = zipFile.getName();
  final String pathFicheroZip = zipFile.getParent();
  
  //Creamos un nuevo fichero zip temporal en la ubicación del zip recibido
  final File ftemp = File.createTempFile(nombreFicheroZip,null,zipFile.getParentFile());
  final FileOutputStream fostemp = new FileOutputStream(ftemp);
  final ZipOutputStream zostemp = new ZipOutputStream(fostemp);
  
  //Abrimos el fichero zip recibido por parametro
  final FileInputStream fis = new FileInputStream(zipFile);
  final ZipInputStream zis = new ZipInputStream(fis);
  
  //Sacammos el contenido del zip recibido por parametro y lo volcamos al zip temporal
  ZipEntry ze = zis.getNextEntry();
  while (ze!= null) {
   ze.getName();
   zostemp.putNextEntry(ze);
   copyToZip(zis, zostemp);
   ze = zis.getNextEntry();
  }
  
  //Añadimos el fichero nuevo al fichero zip temporal
  final ZipEntry zenuevo = new ZipEntry(fichero.getName());
  zostemp.putNextEntry(zenuevo);
  final FileInputStream fisNuevo = new FileInputStream(fichero);
  copyToZip(fisNuevo, zostemp);

  //Cerramos los manejadores
  fisNuevo.close();
  zis.close();
  fis.close();
  zostemp.flush();
  zostemp.closeEntry();
  zostemp.close();
  fostemp.close();

  //Borramos el fichero zip recibido
  zipFile.delete();
  
  //Renombramos el fichero temporal nuevo
  ftemp.renameTo(new File(pathFicheroZip+File.separator+nombreFicheroZip));
 }

 /**
  * Extrae el contenido del zip recibido por parámetro en la carpeta
  * que contiene el fichero zip recibido.
  * 
  * 
  * @param zipFile
  * @throws IOException
  */
 public static void descomprimeZip(final File zipFile) throws IOException {
  
  //Abrimos el fichero zip recibido por parametro
  final FileInputStream fis = new FileInputStream(zipFile);
  final ZipInputStream zis = new ZipInputStream(fis);

  //Extraemos cada fichero del zip en la carpeta del ZIP recibido
  File fe = null;
  FileOutputStream fose = null;
  ZipEntry ze = zis.getNextEntry();
  while (ze!= null) {
   //Procesamos cada fichero del zip
   fe = new File(zipFile.getParentFile().getCanonicalPath()+File.separator+ze.getName());
   fose = new FileOutputStream(fe);
   copyFromZip(zis, fose);
   fose.flush();
   fose.close();
   //Saltamos al siguiente fichero del zip
   ze = zis.getNextEntry();
  }
  
  //Cerramos los manejadores
  zis.close();
  fis.close();  
 }

 private static void copyToZip(final InputStream is, final ZipOutputStream zos) throws IOException {

  byte[] buffer = new byte[BUFFER_SIZE];
  int length;
  while ((length = is.read(buffer)) >= 0) {
   zos.write(buffer, 0, length);
  }
 }
 
 private static void copyFromZip(final ZipInputStream zis, final OutputStream os) throws IOException {

  byte[] buffer = new byte[BUFFER_SIZE];
  int length;
  while ((length = zis.read(buffer)) >= 0) {
   os.write(buffer, 0, length);
  }
 }
}


Un saludo

No hay comentarios:

Publicar un comentario