8 Stimmen

Lesen einer zip-Datei innerhalb einer jar-Datei

Zuvor hatten wir einige Zip-Dateien in unserer Webanwendung. Wir wollten ein bestimmtes Textdokument in der Zip-Datei auslesen. Das war kein Problem:

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
}

Wir haben diese Zip-Dateien jedoch in ein anderes Modul verschoben und wollen sie in ein Jar packen. Leider ist die Erstellung des ZipFile scheitert jetzt. Ich kann eine InputStream für das zip: aber ich habe keine Möglichkeit, einen Eingabestrom 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, einen Eingabestrom für den Eintrag selbst zu erhalten. Ich habe versucht, die Länge des Eintrags zu ermitteln und die nächsten n Bytes aus der Datei ZipInputStream aber das hat bei mir nicht funktioniert. Es schien, dass alle gelesenen Bytes 0 waren.

Gibt es eine Möglichkeit, dieses Problem zu umgehen, oder muss ich die Zip-Dateien zurück in das Kernprojekt verschieben?

7voto

Andy Punkte 4948

Wie wäre es mit TrueZip? Damit können Sie die gezippte Datei einfach so öffnen, als befände sie sich in einem Verzeichnis.

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

Laut der Dokumentation wird auch die unendliche Verschachtelung unterstützt. Ich habe noch nicht tatsächlich dieses Projekt zu verwenden, aber es ist auf meinem Radar für eine Weile gewesen und es scheint für Ihr Problem anwendbar.

Projektstandort: http://truezip.java.net/ (bearbeitet)

4voto

helios Punkte 13224

Eintrag kann Ihnen den Inputstream der inner-zip Datei liefern.

InputStream innerzipstream = zip.getInputStream(entry);

Sie können also verwenden

new ZipInputStream(innerzipstream);

und bitten Sie den ZipInputStream, den Inhalt der inneren Zip-Datei abzurufen (in geordneter Weise, Sie haben keinen zufälligen Zugriff, da es sich um einen ZipInputStream handelt)

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

Sequentieller Zugriff auf den Reißverschluss

Da ZipInputStream eine Zip-Datei aus einem Eingabestrom liest, muss es die Dinge der Reihe nach erledigen:

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

Note : Ich weiß nicht, ob ZipInputStream.getNextEntry() Null zurückgibt, wenn das Ende der Zip-Datei erreicht ist oder nicht. Ich hoffe es, weil ich keine andere Möglichkeit kenne, um zu erkennen, wenn es keine weiteren Einträge gibt.

0voto

Tilak Sharma Punkte 11

Ich habe den oben angegebenen Sequential Zip-Zugangscode geändert:

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

Im obigen Code versuche ich, eine Jar-Datei innerhalb einer anderen Jar-Datei in einen Ordner im Dateisystem zu kopieren. is" ist der Eingabestrom für die Jar-Datei innerhalb einer anderen Jar-Datei (jar.getInputStream("lib/abcd.jar"))

0voto

Ben Punkte 381

Ist es auch möglich, die Zeichenfolge zu analysieren und einen ZipInputStream auf einem anderen ZipInputStream zu öffnen und den Eintrag auf die darin enthaltene Datei zu setzen.

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

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X