2010-11-10 13 views
5

Abbiamo un requisito per determinare se un InputStream in ingresso è un riferimento a un file zip o dati zip. Non abbiamo riferimenti alla fonte sottostante del flusso. Miriamo a copiare il contenuto di questo stream in un OutputStream diretto in una posizione alternativa.Verifica se un flusso è un file zip

Ho provato a leggere il flusso utilizzando ZipInputStream ed estraendo uno ZipEntry. ZipEntry è nullo se lo stream è un file normale, come previsto, tuttavia, nel controllo di uno ZipEntry, ho perso la coppia iniziale di byte dallo stream. Quindi, quando so che lo stream è un flusso regolare, ho già perso i dati iniziali dallo stream.

Qualsiasi idea su come verificare se InputStream è un archivio senza perdita di dati sarebbe utile.

Grazie.

+0

Si prega di vedere i miei commenti alla risposta da Galactus qui sotto - che è l'approccio che sto prendendo come risoluzione. Ringrazia tutti. – AKS

+1

Benvenuti in Stack Overflow! Non dimenticare di contrassegnare la risposta che hai scelto come "selezionata" (il segno di spunta a sinistra). –

+0

Grazie. Appena fatto. – AKS

risposta

6

Supponendo che il flusso di input originale non venga memorizzato nel buffer, proverei a inserire lo stream originale in BufferedInputStream, prima di eseguirne il wrapping in un file ZipInputStream. È possibile utilizzare "mark" e "reset" in BufferedInputStream per tornare alla posizione iniziale nello stream, dopo il controllo.

+0

Grazie. Sto andando "duh!". Sto per provarlo. – AKS

+0

Questo funziona. Sono in grado di avvolgere il mio InputStream originale come BufferedInputStream, impostare un segno e quindi creare un oggetto ZipInputStream per verificare la presenza di uno ZipEntry. Una chiamata reset() e il mio stream è pronto per il riutilizzo. Ora, sperimentando le migliori dimensioni per il buffer. Grazie mille! – AKS

0

Sembra un po 'un trucco, ma è possibile implementare un proxy java.io.InputStream da sedersi tra ZipInputStream e lo stream passato in origine al costruttore di ZipInputStream. Il tuo proxy passerebbe a un buffer finché non saprai se si tratta di un file ZIP o meno. In caso contrario, il buffer salva la giornata.

+0

Sì, sembra un trucco :) .. ma interessante. Sto per provare il suggerimento di Galactus e provare questo se non funziona :) – AKS

0

Hai descritto un java.io.PushbackInputStream - oltre a read(), ha un unread(byte[]) che permette li spinge bck verso la parte anteriore del torrente, e di ri- read() di nuovo.

È in java.io da JDK1.0 (anche se ammetto che non ne ho visto l'uso fino ad oggi).

+0

Ho provato a utilizzare PushbackInputStream. Tuttavia, l'atto di creare un ZipInputStream per verificare se il flusso ha uno ZipEntry e quindi è un archivio, legge i byte in aggiunta alla lettura del flusso Pushback, che vengono persi nella chiamata non letta(). – AKS

+0

@AKS: aspetta, quindi non puoi avvolgere il PBS in ZS? Questo tipo di sconfigge l'utilità del PBS :( – Piskvor

2

È possibile controllare i primi byte di flusso per la firma di intestazione locale ZIP (PK 0x03 0x04), che sarebbe sufficiente per la maggior parte dei casi. Se hai bisogno di maggiore precisione, dovresti prendere gli ultimi ~ 100 byte e controllare i campi del localizzatore di directory centrale.

+0

Sì, questo sembra essere l'approccio più apparente per la verifica del flusso.Tuttavia, capisco, a seconda dello strumento utilizzato per creare lo zip, l'intestazione potrebbe essere diversa. Quindi, anche se il controllo più affidabile, ci siamo allontanati da questo dato che non volevamo controllare ogni possibile intestazione pkzip. – AKS

+0

Per favore fatemi sapere se la differenza tra le intestazioni basate sugli strumenti non è il caso. – AKS

+2

Lo standard ZIP ha un criterio forte per il campo di intestazione locale zip, quindi deve avere lo stesso formato per tutti gli archivi zip. –

2

Ecco come l'ho fatto.

Utilizzare mark/reset per ripristinare lo stream se GZIPInputStream rileva il formato zip errato (lancia l'eccezione ZipException).

/** 
* 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; 
    } 
} 
Problemi correlati