2010-09-14 17 views
6

Zuvor hatten wir einige ZIP-Dateien in unserer Webanwendung. Wir möchten ein bestimmtes Textdokument in der Zip-Datei ablegen. Dies war kein Problem:Eine Zip-Datei in einer JAR-Datei lesen

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 
} 

Allerdings haben wir diese Zip-Dateien in ein anderes Modul verschoben und möchten sie in einem Glas verpacken. Leider schlägt das Erstellen der ZipFile jetzt fehl. Ich kann eine InputStream für die ZIP bekommen: aber ich habe keine Möglichkeit, einen Input-Stream für den Eintrag selbst zu erhalten.

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

aber ich habe keine Möglichkeit, sich um einen Eingangsstrom für den Eintritt von zu bekommen. Ich habe versucht, die Länge des Eintrags zu finden und die nächsten n Bytes aus der ZipInputStream zu bekommen, aber das hat nicht für mich funktioniert. Es schien, dass alle gelesenen Bytes 0 waren.

Gibt es einen Weg um dies oder muss ich die Zip-Dateien zurück in das Kernprojekt verschieben?

Antwort

4

Eintrag kann Ihnen den Eingangsstrom der inneren Zip-Datei geben.

InputStream innerzipstream = zip.getInputStream(entry); 

So können Sie

new ZipInputStream(innerzipstream); 

verwenden und die ZipInputStream bitten, den Inhalt der Innen-zip-Datei (in einer geordneten Art und Weise abzurufen, Sie haben nicht zufällig Zugriff, weil es ein ZipInputStream ist

)

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

Sequential RV-Zugang

Wie ZipInputStream liest eine Zip-Datei von einem Eingangsstrom es Dinge, um zu tun hat:

// 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(); 

Hinweis: Ich weiß nicht, ob ZipInputStream.getNextEntry() null zurückgibt, wenn Ende zip Datei ist erreicht oder nicht. Ich hoffe es, weil ich keine andere Möglichkeit weiß zu erkennen, wenn es keine Einträge mehr gibt.

+0

In der Tat können Sie Class.getResourceAsStream und ZipInputStream verwenden, um die äußere zu lesen -zip auch. Auf diese Weise brauchen Sie den Ad-hoc-Dateinamen nicht ersetzen und verlassen sich nicht auf URL für den Dateizugriff. – helios

6

Wie wäre es mit TrueZip? Mit ihr können Sie die gezippte Datei einfach öffnen, als ob sie sich in einem Verzeichnis befand.

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

Gemäß den Dokumenten wird auch die unendliche Verschachtelung unterstützt. Ich habe dieses Projekt noch nicht benutzt, aber es ist schon eine Weile auf meinem Radar und es scheint auf Ihr Problem anwendbar zu sein.

Projekt-Website: http://truezip.java.net/ (bearbeitet)

0

Ich habe die Sequential Zip Zugangscode geändert bereitgestellt oben:

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

In dem obigen Code, ich versuche, eine Jar-Datei in einer anderen Jar-Datei zu kopieren in einen Ordner im Dateisystem. ‚ist‘ ist, der Eingangsstrom in die JAR-Datei in einer anderen JAR-Datei (jar.getInputStream („lib/abcd.jar“))

0

es ist auch möglich, die Zeichenfolge zu analysieren und ein auf einem anderen ZipInputStream ZipInputStream zu öffnen, und setze den Eintrag in die Datei hinein.

z.B. Sie haben den String wie oben "path/to/some-jar.jar/intern/zip/file.zip/myfile.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; 
}