2010-01-18 18 views
21

tenemos un código que genera un archivo zip en nuestro sistema. Todo está bien, pero a veces este archivo comprimido abierto por FilZip o WinZip se considera dañado.¿Cómo comprobar si un archivo zip generado está dañado?

Así que aquí está mi pregunta: ¿cómo podemos comprobar programáticamente si un archivo zip generado está dañado?

Este es el código que estamos utilizando para generar nuestros archivos zip:

try { 
    ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(tmpFile)); 
    byte[] buffer = new byte[16384]; 
    int contador = -1; 
    for (DigitalFile digitalFile : document.getDigitalFiles().getContent()) { 
     ZipEntry entry = new ZipEntry(digitalFile.getName()); 
     FileInputStream fis = new FileInputStream(digitalFile.getFile()); 
     try { 
      zos.putNextEntry(entry); 
      while ((counter = fis.read(buffer)) != -1) { 
      zos.write(buffer, 0, counter); 
      } 
      fis.close(); 
      zos.closeEntry(); 
     } catch (IOException ex) { 
      throw new OurException("It was not possible to read this file " + arquivo.getId()); 
     } 
    } 
    try { 
     zos.close(); 
    } catch (IOException ex) { 
     throw new OurException("We couldn't close this stream", ex); 
    } 

¿Hay algo que estamos haciendo mal aquí?

EDITAR: En realidad, el código anterior está absolutamente bien. Mi problema era que estaba redireccionando la transmisión INCORRECTA para mis usuarios. Entonces, en lugar de abrir un archivo zip, abrían algo completamente diferente. mea culpa :(

pero la cuestión principal sigue siendo: ¿cómo programáticamente puedo verificar si un archivo zip dado no está dañado

+0

Solo un problema adicional: zos no se cerrará si se produce una excepción. ¿Podría pegar el resto del try/catch/finally externo? –

Respuesta

25

Usted puede utilizar la clase ZipFile para comprobar su archivo:

static boolean isValid(final File file) { 
    ZipFile zipfile = null; 
    try { 
     zipfile = new ZipFile(file); 
     return true; 
    } catch (IOException e) { 
     return false; 
    } finally { 
     try { 
      if (zipfile != null) { 
       zipfile.close(); 
       zipfile = null; 
      } 
     } catch (IOException e) { 
     } 
    } 
} 
+0

¡Perfecto! No sabía esta clase. ¡Muchas gracias! –

+1

Si desea probar todo el archivo zip (no solo compruebe si tiene cabezales zip), haga una lectura completa de él usando un archivo zip (repita las entradas y pregunte por la secuencia y léala hasta que termine) . – helios

+2

El formato de archivo zip es redundante, por lo que no puede asegurarse de que no está dañado. Lo mejor que puede hacer sin tener su propia implementación es leer todos los datos a través de 'ZipFile' y mediante' ZipInputStream' y comparar hashes seguros. –

3

Creo verá seguimiento de la pila excepción corresponsal durante la generación del archivo zip?. .. Por lo tanto, es probable que wa no para mejorar su manejo de excepciones

+0

En realidad, no se lanza ninguna excepción en el proceso. El archivo zip está completamente generado, pero no podemos abrirlo con Filzip, Winzip o cualquier otra aplicación de extracción de zip. :/ –

0

ZipOutputStream does not close la corriente subyacente

lo que hay que hacer es:

FileOutputStream fos = new FileOutputStream(...); 
ZipOutputStream zos = new ZipOutputStream(fos); 

A continuación, en el bloque de cierre:

zos.close(); 
fos.flush(); // Can't remember whether this is necessary off the top of my head! 
fos.close(); 
+0

Bueno, lo intenté, pero el problema persiste. En realidad, nuestro problema está sucediendo en un solo caso solamente. :/ –

+0

'ZipOutputStream no cierra la secuencia subyacente' - esto parece estar mal. finish() no se cierra, pero close() lo hace. Esto se puede verificar en el origen del método DeflaterOutputStream # close(). – Vadzim

1

Quizás intercambiar las dos líneas siguientes ?;

fis.close(); 
zos.closeEntry(); 

Me imagino que closeEntry() todavía leerá algunos datos de la secuencia.

+0

El problema persiste. :/ –

1

Su código es básicamente correcto, intente averiguar qué archivo es responsable del archivo zip dañado. Compruebe si digitalFile.getFile() siempre devuelve un argumento válido y accesible para FileInputStream. Simplemente agrega un bit de registro a tu código y descubrirás qué está mal.

2

en mi aplicación se ve así. tal vez le ayuda a:

//[...] 

try { 
    FileInputStream fis = new FileInputStream(file); 
    BufferedInputStream bis = new BufferedInputStream(fis); 

    zos.putNextEntry(new ZipEntry(file.getName())); 

    try { 
     final byte[] buf = new byte[BUFFER_SIZE]; 
     while (true) { 
      final int len = bis.read(buf); 
      if (len == -1) { 
       break; 
      } 
      zos.write(buf, 0, len); 
     } 
     zos.flush(); 
     zos.closeEntry(); 
    } finally { 
     try { 
      bis.close(); 
     } catch (IOException e) { 
      LOG.debug("Buffered Stream closing failed"); 
     } finally { 
      fis.close(); 
     } 
    } 
} catch (IOException e) { 
    throw new Exception(e); 
} 

//[...] 
zos.close 
1
new ZipFile(file) 

compresa de nuevo el archivo, por lo que duplicar esfuerzos y eso no es lo que busca. A pesar de que solo verifica un archivo y la pregunta comprime n-files.

Echa un vistazo a esto: http://www.kodejava.org/examples/336.html

Crear una suma de comprobación para su postal:

CheckedOutputStream checksum = new CheckedOutputStream(fos, new CRC32()); 
ZipOutputStream zos = new ZipOutputStream(new BufferedOutputStream(checksum)); 
... 

Y cuando termine el programa de compresión que

System.out.println("Checksum : " + checksum.getChecksum().getValue()); 

que debe hacer la misma lectura el zip con java u otras herramientas que comprueban si las sumas de comprobación coinciden.

ver https://stackoverflow.com/a/10689488/848072 para más información

8

Sé que ha pasado un tiempo que esto ha sido publicado, he utilizado el código que todos ustedes proporcionan y se acercó con esto. Esto funciona de maravilla para la pregunta real. Comprobando si el archivo zip está dañado o no

private boolean isValid(File file) { 
    ZipFile zipfile = null; 
    ZipInputStream zis = null; 
    try { 
     zipfile = new ZipFile(file); 
     zis = new ZipInputStream(new FileInputStream(file)); 
     ZipEntry ze = zis.getNextEntry(); 
     if(ze == null) { 
      return false; 
     } 
     while(ze != null) { 
      // if it throws an exception fetching any of the following then we know the file is corrupted. 
      zipfile.getInputStream(ze); 
      ze.getCrc(); 
      ze.getCompressedSize(); 
      ze.getName(); 
      ze = zis.getNextEntry(); 
     } 
     return true; 
    } catch (ZipException e) { 
     return false; 
    } catch (IOException e) { 
     return false; 
    } finally { 
     try { 
      if (zipfile != null) { 
       zipfile.close(); 
       zipfile = null; 
      } 
     } catch (IOException e) { 
      return false; 
     } try { 
      if (zis != null) { 
       zis.close(); 
       zis = null; 
      } 
     } catch (IOException e) { 
      return false; 
     } 

    } 
} 
+0

desearía poder darle múltiples votos para esto. ¡Gracias! – Jim

+0

¡Gracias por esto! Una sugerencia, podría simplificarlo un poco utilizando ZipFile.entries() para obtener cada ZipEntry, ahorrándose la molestia de crear (y cerrar) ZipInputStream. – svattom

+0

ze.get *() no hace nada. Usted puede ver aquí: http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/zip/ZipEntry.java#ZipEntry – joseph

Cuestiones relacionadas