2009-11-27 14 views

risposta

21

Il magic bytes per il formato ZIP è 50 4B. È possibile testare lo stream (utilizzando mark e reset - potrebbe essere necessario il numero buffer) ma non mi aspetto che questo sia un approccio affidabile al 100%. Non ci sarebbe modo di distinguerlo da un file di testo codificato US-ASCII iniziato con le lettere PK.

Il migliore sarebbe fornire i metadati nel formato di contenuto prima di aprire lo stream e quindi trattarlo in modo appropriato.

5

Non molto elegante, ma affidabile:

se il flusso può essere letta tramite ZipInputStream, occorre zip.

+1

Semplicemente non sembra carino. Non potrebbe essere un flusso ZIP corrotto? – Fedearne

+10

@fedearne: è un flusso zip danneggiato un flusso zip? – GvS

+2

Accetto: Se ZipInputStream non riesce a leggerlo, non è * importante * che sia "significato" come file Zip. Destra? –

6

Si potrebbe verificare che i primi quattro byte del torrente sono la firma intestazione del file locale che avvia il file locale di intestazione che procede ogni file in un file ZIP, as shown in the spec here essere 50 4B 03 04.

Un codice di prova piccoli spettacoli far funzionare tutto questo:

byte[] buffer = new byte[4]; 

try { 
    ZipOutputStream zos = new ZipOutputStream(new FileOutputStream("so.zip")); 
    ZipEntry ze = new ZipEntry("HelloWorld.txt"); 
    zos.putNextEntry(ze); 
    zos.write("Hello world".getBytes()); 
    zos.close(); 

    FileInputStream is = new FileInputStream("so.zip"); 
    is.read(buffer); 
    is.close(); 
} 
catch(IOException e) { 
    e.printStackTrace(); 
} 

for (byte b : buffer) { 
    System.out.printf("%H ",b); 
} 

mi ha dato questo output:

50 4B 3 4 
+1

Ho avuto la stessa idea (anche se Wikipedia di fiducia rispetto alle specifiche - per vergogna!), Ma sembra che questo non sia un meccanismo affidabile: _ "Gli implementatori devono essere consapevoli che i file ZIP possono essere incontrati con o senza questa firma e dovrebbe tenere conto di entrambi i casi durante la lettura di file ZIP per garantire la compatibilità. "_ – McDowell

+1

Questo è vero per una prospettiva generale, ma suppongo che se non si ha la firma ZipInputStream avrà esito negativo come insiste sugli oggetti ZipEntry. –

+1

È possibile inserire un file spazzatura casuale anteposto ai file zip (come gli eseguibili di Microsoft Windows). Funzionano solo se si utilizza la directory centrale anziché lo streaming con intestazioni locali. FWIW, Java PlugIn e WebStart utilizzano la directory centrale ma ora controllano anche i primi quattro byte (vedere i GIAR). –

35

Introduzione

Dal momento che tutte le risposte sono 5 anni mi sento un dovere di scrivere, cosa sta succedendo oggi. Dubito seriamente che si dovrebbero leggere i byte magici del flusso! Questo è un codice di basso livello, dovrebbe essere evitato in generale.

Risposta semplice

Miku scrive:

se il flusso può essere letta tramite ZipInputStream, deve essere compresso.

Sì, ma in caso di ZipInputStream "si può leggere" significa che prima chiamata a .getNextEntry() restituisce un valore non nullo. Nessuna eccezione che cattura eccetera. Così, invece di byte magici parsing solo si può fare:

boolean isZipped = new ZipInputStream(yourInputStream).getNextEntry() != null; 

E il gioco è fatto!

generali pensieri di decompressione

In generale, è risultato che è molto più conveniente per lavorare con i file, mentre [un] zippare, che con i flussi. Ci sono diverse librerie utili, oltre a ZipFile ha più funzionalità di ZipInputStream. La gestione dei file zip è discussa qui: What is a good Java library to zip/unzip files? Quindi se si può lavorare con i file è meglio farlo!

Esempio di codice

ho bisogno nella mia richiesta di lavorare solo con i flussi. Quindi questo è il metodo che ho scritto per decomprimerlo:

import org.apache.commons.io.IOUtils; 
import java.util.zip.ZipEntry; 
import java.util.zip.ZipInputStream; 

public boolean unzip(InputStream inputStream, File outputFolder) throws IOException { 

    ZipInputStream zis = new ZipInputStream(inputStream); 

    ZipEntry entry; 
    boolean isEmpty = true; 
    while ((entry = zis.getNextEntry()) != null) { 
     isEmpty = false; 
     File newFile = new File(outputFolder, entry.getName()); 
     if (newFile.getParentFile().mkdirs() && !entry.isDirectory()) { 
      FileOutputStream fos = new FileOutputStream(newFile); 
      IOUtils.copy(zis, fos); 
      IOUtils.closeQuietly(fos); 
     } 
    } 

    IOUtils.closeQuietly(zis); 
    return !isEmpty; 
} 
+1

Ci sono situazioni in cui un 'ZipOutputStream' non è finito o chiuso correttamente che significherà che il file risultante genererà una' IOException' quando viene analizzata in un 'nuovo ZipFile (f)' perché non è valido. Quanto sopra non fallirà, anche quando il file zip non è valido per altri scopi. –

0

Controllare il numero magico potrebbe non essere l'opzione giusta.

I file Docx hanno anche un numero magico simile 50 4B 3 4

+2

Ecco perché i file docx sono file zip. – tak3shi

Problemi correlati