2010-11-10 2 views
5

Wir müssen festlegen, ob ein eingehender InputStream ein Verweis auf eine Zip-Datei oder Zip-Daten ist. Wir haben keinen Bezug zur zugrunde liegenden Quelle des Streams. Wir beabsichtigen, den Inhalt dieses Streams in einen OutputStream zu kopieren, der an einen anderen Ort gerichtet ist.Überprüfen, ob ein Stream eine Zip-Datei ist

Ich habe versucht, den Stream mit ZipInputStream zu lesen und einen ZipEntry extrahieren. Der ZipEntry ist null, wenn der Stream wie erwartet eine reguläre Datei ist. Beim Überprüfen auf einen ZipEntry verliere ich jedoch die ersten paar Bytes aus dem Stream. Wenn ich weiß, dass der Stream ein regulärer Stream ist, habe ich bereits erste Daten aus dem Stream verloren.

Alle Überlegungen zur Überprüfung, ob der InputStream ein Archiv ohne Datenverlust ist, wären hilfreich.

Danke.

+0

Bitte beachten Sie meine Kommentare zu der Antwort von Galactus unten - welches ist der Ansatz, den ich als eine Lösung nehme. Danke allen. – AKS

+1

Willkommen bei Stack Overflow! Vergessen Sie nicht, die Antwort, die Sie gewählt haben, als "ausgewählt" zu markieren (die Häkchenumrandung auf der linken Seite). –

+0

Danke. Gerade gemacht. – AKS

Antwort

6

Angenommen, Ihr ursprünglicher Eingabestream wird nicht gepuffert, würde ich versuchen, den ursprünglichen Stream in einem BufferedInputStream zu verpacken, bevor Sie ihn in einen ZipInputStream zum Überprüfen einbinden. Sie können "mark" und "reset" in BufferedInputStream verwenden, um nach der Überprüfung zur ursprünglichen Position im Stream zurückzukehren.

+0

Danke. Ich gehe 'duh!'. Ich werde es versuchen. – AKS

+0

Das funktioniert. Ich bin in der Lage, meinen ursprünglichen InputStream als BufferedInputStream zu verpacken, eine Markierung zu setzen und dann einen ZipInputStream zu erstellen, um nach einem ZipEntry zu suchen. Ein Reset() Anruf und mein Stream ist bereit für die Wiederverwendung. Jetzt experimentieren Sie mit der besten Größe für den Puffer. Vielen Dank ! – AKS

0

Es klingt ein wenig wie ein Hack, aber Sie könnten einen Proxy java.io.InputStream implementieren, um zwischen ZipInputStream und dem Stream zu sitzen, den Sie ursprünglich an den Konstruktor von ZipInputStream übergaben. Ihr Proxy würde in einen Puffer streamen, bis Sie wissen, ob es sich um eine ZIP-Datei handelt oder nicht. Wenn nicht, dann speichert der Puffer Ihren Tag.

+0

Ja, es klingt wie ein Hack :) .. aber ein interessanter. Ich bin im Begriff, den Vorschlag von Galactus zu versuchen und dieses zu versuchen, wenn das nicht funktioniert :) – AKS

0

Sie haben eine java.io.PushbackInputStream beschrieben - neben read() es eine unread(byte[]) hat, die man ihnen erlaubt, schieben BCK an der Vorderseite des Stroms und read() sie wieder re-.

Es ist in java.io seit JDK1.0 (obwohl ich zugeben, ich habe bis heute keinen Gebrauch dafür gesehen).

+0

Ich habe versucht, den PushbackInputStream zu verwenden. Der Vorgang des Erstellens eines ZipInputStream, um zu überprüfen, ob der Stream einen ZipEntry aufweist und daher ein Archiv ist, liest zusätzlich zum Lesen des Pushback-Streams Bytes, die beim Aufruf von unread() verloren gehen. – AKS

+0

@AKS: Warte, du kannst das PBS nicht in ZS wickeln? Das vereitelt die Nützlichkeit des PBS :( – Piskvor

2

Sie können die ersten Bytes des Streams für die lokale ZIP-Headersignatur (PK 0x03 0x04) überprüfen, das reicht für die meisten Fälle. Wenn Sie mehr Genauigkeit benötigen, sollten Sie die letzten ~ 100 Bytes nehmen und nach zentralen Verzeichnis-Locator-Feldern suchen.

+0

Ja, das schien der offensichtlichste Ansatz für die Verifizierung des Streams zu sein.Ich verstehe jedoch, dass die Kopfzeile je nach dem Tool, das zum Erstellen der ZIP verwendet wird, unterschiedlich sein kann. Daher haben wir uns, obwohl dies die zuverlässigste Prüfung war, davon entfernt, da wir nicht nach jedem möglichen PKZIP-Header suchen wollten. – AKS

+0

Bitte lassen Sie mich wissen, wenn der Unterschied in Headern basierend auf Tools nicht der Fall ist. – AKS

+2

Der ZIP-Standard hat ein starkes Kriterium für das zip-lokale Header-Feld, daher muss er das gleiche Format für alle Zip-Archive haben. –

2

So habe ich es gemacht.

Verwenden Sie mark/reset, um den Stream wiederherzustellen, wenn der GZIPInputStream ein falsches Zip-Format erkennt (löst die ZipException aus).

/** 
* Wraps the input stream with GZIPInputStream if needed. 
* @param inputStream 
* @return 
* @throws IOException 
*/ 
private InputStream wrapIfZip(InputStream inputStream) throws IOException { 
    if (!inputStream.markSupported()) { 
     inputStream = new BufferedInputStream(inputStream); 
    } 
    inputStream.mark(1000); 
    try { 
     return new GZIPInputStream(inputStream); 
    } catch (ZipException e) { 
     inputStream.reset(); 
     return inputStream; 
    } 
}