2010-01-18 5 views
21

Wir haben einen Code, der eine Zip-Datei auf unserem System erzeugt. Alles ist in Ordnung, aber manchmal wird diese Zip-Datei, die von FilZip oder WinZip geöffnet wurde, als beschädigt betrachtet.Wie überprüft man, ob eine generierte Zip-Datei beschädigt ist?

Also hier ist meine Frage: Wie können wir überprüfen, ob eine generierte ZIP-Datei beschädigt ist?

Hier ist der Code, den wir unsere Zip-Dateien zu erzeugen, verwenden:

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); 
    } 

Gibt es alles, was wir falsch hier?

EDIT: Eigentlich ist der obige Code absolut in Ordnung. Mein Problem war, dass ich den WRONG-Stream für meine Benutzer umgeleitet habe. Anstatt eine Zip-Datei zu öffnen, öffneten sie etwas völlig anderes. Mea culpa :(

aber die Hauptfrage bleibt: wie programmatisch kann ich überprüfen, ob eine bestimmte ZIP-Datei nicht beschädigt ist

+0

Nur ein zusätzliches Problem: zos wird nicht geschlossen, wenn eine Ausnahme ausgelöst wird. Könntest du den Rest des äußeren try/catch/schließlich einfügen? –

Antwort

25

können Sie die ZipFile-Klasse verwenden, um Ihre Datei zu überprüfen:

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

Perfekt! Ich kannte diese Klasse nicht. Danke vielmals! –

+1

Wenn Sie die gesamte ZIP-Datei testen wollen (nicht nur, ob sie Zip-Köpfe hat), dann lesen Sie sie komplett mit Zip-Datei (iterieren Sie die Einträge und fragen Sie nach dem Stream und lesen Sie ihn bis zum Ende) . – helios

+2

Das Zip-Dateiformat ist redundant, daher können Sie nicht sicher sein, dass es nicht beschädigt ist. Am besten können Sie ohne eigene Implementierung alle Daten durch 'ZipFile' und durch' ZipInputStream' lesen und sichere Hashes vergleichen. –

3

Ich denke, Sie Korrespondent Ausnahme-Stack-Trace während Zip-Datei Generation sehen?. .. Also, werden Sie wahrscheinlich wan't auf Ihre Ausnahmebehandlung verbessern

+0

Tatsächlich wird keine Ausnahme in den Prozess geworfen. Die Zip-Datei ist vollständig generiert, aber wir können sie nicht mit Filzip, Winzip oder einer anderen Zip-Extraktionsanwendung öffnen. :/ –

0

ZipOutputStream does not close der zugrunde liegenden Stream

Was Sie tun müssen, ist:

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

Dann in Ihrem Schließblock:

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

Nun: Ich habe es versucht, aber das Problem bleibt bestehen. Tatsächlich passiert unser Problem nur in einem einzigen Fall. :/ –

+0

'ZipOutputStream schließt den zugrunde liegenden Stream nicht '- das scheint falsch zu sein. finish() schließt nicht, aber close() tut es. Dies kann in der Quelle der Methode DeflaterOutputStream # close() verifiziert werden. – Vadzim

1

Vielleicht die folgenden zwei Zeilen tauschen ?;

Ich kann mir vorstellen, dass der closeEntry() noch einige Daten aus dem Stream lesen wird.

+0

Das Problem bleibt bestehen. :/ –

1

Ihr Code ist grundsätzlich in Ordnung, versuchen Sie herauszufinden, welche Datei für die beschädigte ZIP-Datei verantwortlich ist. Überprüfen Sie, ob digitalFile.getFile() immer ein gültiges und zugreifbares Argument an FileInputStream zurückgibt. Fügen Sie Ihrem Code einfach ein wenig Logging hinzu und Sie werden herausfinden, was nicht stimmt.

2

in meiner Implementierung sieht es so aus. vielleicht hilft es Ihnen:

//[...] 

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) 

Kompresse wieder die Datei, so dass doppelte Arbeit, und das ist nicht das, was Sie suchen. Trotz der Tatsache, dass nur eine Datei überprüft und die Frage n-Dateien komprimiert werden.

einen Blick auf diese nehmen: http://www.kodejava.org/examples/336.html

eine Prüfsumme für Ihre Zip erstellen:

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

Und wenn man die Show es Kompression beenden

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

Sie müssen die gleichen Lese tun Die Zip mit Java oder anderen Tools überprüft, ob Prüfsummen übereinstimmen.

siehe https://stackoverflow.com/a/10689488/848072 für weitere Informationen

8

Ich weiß, es ist eine Weile, dass dies geschrieben wurde, ich den Code verwendet haben, die alle von Ihnen zur Verfügung gestellten und kam mit dieser. Dies funktioniert gut für die eigentliche Frage. Überprüfen, ob die Zip-Datei beschädigt ist oder nicht

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

Ich wünschte, ich könnte Ihnen dafür mehrere Stimmen geben. Vielen Dank! – Jim

+0

Danke dafür! Ein Vorschlag, Sie könnten dies ein wenig vereinfachen, indem Sie ZipFile.entries() verwenden, um jeden ZipEntry zu erhalten, was den Aufwand beim Erstellen (und Schließen) von ZipInputStream erspart. – svattom

+0

ze.get *() tut nichts. Sie können hier sehen: http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/zip/ZipEntry.java#ZipEntry – joseph