2010-09-14 6 views
6

Precedentemente avevamo alcuni file zip all'interno della nostra applicazione web. Vorremmo mettere un documento di testo specifico all'interno del file zip. Questo non era un problema:Lettura di un file zip all'interno di un file jar

URL url = getClass().getResource(zipfile); 
ZipFile zip = new ZipFile(url.getFile().replaceAll("%20", " "));  
Entry entry = zip.getEntry("file.txt"); 

InputStream is = zip.getInputStream(entry); 
BufferedReader reader = new BufferedReader(new InputStreamReader(is)); 

String line = reader.readLine(); 
while (line != null) { 
    // do stuff 
} 

Tuttavia ci siamo spostati questi file zip in un altro modulo e vogliamo loro pacchetto all'interno di un barattolo. Sfortunatamente, la creazione di ZipFile non riesce. Posso ottenere un InputStream per il file zip: ma non ho modo di ottenere un flusso di input per la voce stessa.

InputStream is = getClass().getResourceAsStream(zipfile); 
ZipInputStream zis = new ZipInputStream(is); 

ZipEntry entry = zis.getNextEntry(); 
while (entry != null && !entry.getName().equals("file.txt")) { 
    entry = zis.getNextEntry(); 
} 

ma non ho modo di ottenere un flusso di input per la voce stessa. Ho provato a trovare la lunghezza della voce e ottenere i successivi n byte dal ZipInputStream ma questo non ha funzionato per me. Sembrava che tutti i byte letti fossero 0.

C'è un modo per aggirare questo o dovrò spostare i file zip nel progetto principale?

risposta

4

voce può fornire l'inputstream del file zip interno.

InputStream innerzipstream = zip.getInputStream(entry); 

Così si può utilizzare

new ZipInputStream(innerzipstream); 

e chiedere al ZipInputStream per recuperare il contenuto del-file zip interna (in modo ordinato, non si dispone di accesso casuale perché è uno ZipInputStream)

Guarda http://download.oracle.com/javase/1.4.2/docs/api/java/util/zip/ZipInputStream.html

accesso sequenziale zip

Come ZipInputStream sta leggendo un file zip da un ingresso streaming ha a che fare le cose in ordine:

// DO THIS for each entry 
ZipEntry e = zipInputStreamObj.getNextEntry(); 
e.getName // and all data 
int size = e.getSize(); // the byte count 
while (size > 0) { 
    size -= zipInputStreamObj.read(...); 
} 
zipInputStreamObj.closeEntry(); 
// DO THIS END 

zipInputStreamObj.close(); 

Nota: Non so se ZipInputStream.getNextEntry() restituisce null quando fine della zip il file viene raggiunto o meno. Lo spero perché non conosco altro modo per capire quando non ci sono più voci.

+0

In realtà, è possibile utilizzare Class.getResourceAsStream e ZipInputStream di leggere quello esterno -scarica troppo. In questo modo, non è necessario sostituire il nome del file ad hoc e non fare affidamento sull'URL per l'accesso ai file. – helios

6

Che ne dici di TrueZip? Usandolo si potrebbe semplicemente aprire il file zippato come se si trovasse all'interno di una directory.

new FileOutputStream("/path/to/some-jar.jar/internal/zip/file.zip/myfile.txt"); 

Secondo i documenti, è supportata anche la nidificazione infinita. Devo ancora utilizzare effettivamente questo progetto, ma è stato sul mio radar per un po 'e sembra applicabile al tuo problema.

progetto del sito: http://truezip.java.net/ (Edited)

0

Ho modificato il codice di accesso sequenziale postale fornito sopra:

File destFile = new File(destDir, jarName); 
JarOutputStream jos = new JarOutputStream(new FileOutputStream(destFile)); 

JarInputStream jis = new JarInputStream(is); 
JarEntry jarEntry = jis.getNextJarEntry(); 
for (; jarEntry != null ; jarEntry = jis.getNextJarEntry()) { 
    jos.putNextEntry(new JarEntry(jarEntry.getName())); 
    if(jarEntry.isDirectory()) { 
     continue; 
    } 

    int bytesRead = jis.read(buffer); 
    while(bytesRead != -1) { 
    jos.write(buffer, 0, bytesRead); 
    bytesRead = jis.read(buffer); 
    } 

} 
is.close(); 
jis.close(); 
jos.flush(); 
jos.closeEntry(); 
jos.close(); 

Nel codice di cui sopra, sto cercando di copiare un file Jar all'interno di un altro file Jar in una cartella nel file system. "is" è il flusso di input del file jar all'interno di un altro file jar (jar.getInputStream ("lib/abcd.jar"))

0

è anche possibile analizzare la stringa e aprire un ZipInputStream su un altro ZipInputStream e imposta la voce nel file all'interno.

ad es. avete la stringa come sopra "path/to/some-jar.jar/interno/zip/file.zip/miofile.txt"

private static final String[] zipFiles = new String[] { ".zip", ".jar" }; 

public static InputStream getResourceAsStream(final String ref) throws IOException { 
    String abstractPath = ref.replace("\\", "/"); 
    if (abstractPath.startsWith("/")) { 
     abstractPath = abstractPath.substring(1); 
    } 
    final String[] pathElements = abstractPath.split("/"); 
    return getResourceAsStream(null, pathElements); 
} 

private static InputStream getResourceAsStream(final ZipInputStream parentStream, final String[] pathElements) 
     throws IOException { 

    if (pathElements.length == 0) return parentStream; 

    final StringBuilder nextFile = new StringBuilder(); 
    for (int index = 0; index < pathElements.length; index++) { 
     final String pathElement = pathElements[index]; 
     nextFile.append((index > 0 ? "/" : "") + pathElement); 
     if (pathElement.contains(".")) { 
      final String path = nextFile.toString(); 
      if (checkForZip(pathElement)) { 
       final String[] restPath = new String[pathElements.length - index - 1]; 
       System.arraycopy(pathElements, index + 1, restPath, 0, restPath.length); 
       if (parentStream != null) { 
        setZipToEntry(parentStream, path); 
        return getResourceAsStream(new ZipInputStream(parentStream), restPath); 
       } else return getResourceAsStream(new ZipInputStream(new FileInputStream(path)), restPath); 
      } else { 
       if (parentStream != null) { 
        setZipToEntry(parentStream, path); 
        return parentStream; 
       } else return new FileInputStream(path); 
      } 
     } 
    } 
    throw new FileNotFoundException("File not found: " + nextFile.toString()); 
} 

private static void setZipToEntry(final ZipInputStream in, final String name) throws IOException { 
    ZipEntry entry; 
    while ((entry = in.getNextEntry()) != null) { 
     if (entry.getName().equals(name)) return; 
    } 
    throw new FileNotFoundException("File not found: " + name); 
} 

private static boolean checkForZip(final String ref) { 
    for (final String zipFile : zipFiles) { 
     if (ref.endsWith(zipFile)) return true; 
    } 
    return false; 
}