0

I am able to iterate over ZipEntrys of a ZipInputStream like this:

ByteArrayInputStream schema = new ByteArrayInputStream(schemaData);
ZipInputStream zis = new ZipInputStream(schema);
ZipEntry entry;
while((entry = zis.getNextEntry()) != null) {
     String entryName = entry.getName();
     // filter based on entry name
     // how to copy this entry?
}

How can I copy certain entries of this Zip file?

xtratic
  • 4,600
  • 2
  • 14
  • 32
Gordon
  • 85
  • 1
  • 11

1 Answers1

1

Yes it is certainly possible. When you call ZipInputStream.getNextEntry() it positions the stream at the start of the next entry of data, in this case you want the data when it's a sub zip file. The stream wont go past the end of that data so don't worry about reading into the next entry, the entries of a ZipInputStream can essentially be treated like an individual stream of their own.

public static void main(String[] args) throws IOException {
    // ** specify an output directory to copy files to
    final File outDir = new File("path\\to\\...\\OutDir");

    // ** read the zip input stream and do for each entry...
    final String pathToZip = "path\\to\\...\\ZipTest.zip";
    try (InputStream is = new FileInputStream(pathToZip);
            ZipInputStream zis = new ZipInputStream(is);) {

        forEachZipEntry(zis, (zipEntry, subZipStream) -> {
            // ** specify how to consume each zip entry and stream...
            // ** apply filters here, based on the zip entry
            if (zipEntry.getName().equals("normalZippedDir.zip")) {
                // ** copy the zip stream to the file
                File outFile = new File(outDir, zipEntry.getName());
                try (FileOutputStream fis = new FileOutputStream(outFile);) {
                    // apache IOUtils or whatever copy method you want
                    IOUtils.copy(subZipStream, fis);
                } catch (IOException e) { e.printStackTrace(); }
            }
        });
    }
}

/**
 * Iterates through all {@linkplain ZipEntry}s of the given {@linkplain ZipInputStream} and
 * passes the current zip entry and stream to the provided {@linkplain BiConsumer}, but does
 * <b>not</b> recursively parse entries of nested zip files.
 */
public static void forEachZipEntry(ZipInputStream zis, BiConsumer<ZipEntry, ZipInputStream> consumer)
        throws IOException {
    Objects.requireNonNull(zis);
    Objects.requireNonNull(consumer);
    ZipEntry entry;
    while ((entry = zis.getNextEntry()) != null) {
        consumer.accept(entry, zis);
    }
}

/**
 * Recursively iterates through <b>all</b> {@linkplain ZipEntry}s <i>(including entries of nested zip
 * files)</i> of the given {@linkplain ZipInputStream} passing the current zip entry and stream to
 * the provided {@linkplain BiConsumer}.
 */
public static void forEachZipEntryRecursive(ZipInputStream zis,
        BiConsumer<ZipEntry, ZipInputStream> consumer) throws IOException {
    Objects.requireNonNull(zis);
    Objects.requireNonNull(consumer);
    ZipEntry entry;
    while ((entry = zis.getNextEntry()) != null) {
        consumer.accept(entry, zis);
        @SuppressWarnings("resource") // ** caller shall close `zis`
        ZipInputStream subZis = new ZipInputStream(zis);
        forEachZipEntryRecursive(subZis, consumer);
    }
}
xtratic
  • 4,600
  • 2
  • 14
  • 32
  • so if I understood right : if the name of the file contains zip of the current entry,then copy all elements from the next entry to the end to subZipInputStream? – Gordon Jul 11 '18 at 13:05
  • The name doesn't guarantee that it's a Zip file or not so you should handle exceptions; However `.zip` and `.jar` usually are Zip files unless creator of the files is lying about their file type. Once you have your sub zip input stream, you can do whatever you like with it, if you want to copy its elements then go ahead. – xtratic Jul 11 '18 at 13:38
  • @Gordon If this answered your question, please accept it. – xtratic Jul 11 '18 at 17:11
  • I don't think that solves my question because the code is cutting the left side of the stream and returns the right which is kind of filtering but not full filtering (imagine 4 entries and I want to get the second and fourth then this code will get me only the fourth) – Gordon Jul 12 '18 at 10:22
  • @Gordon Cutting the left side of the stream? Have you run this code? It's iterating through *all* entries and sub-entries of the Zip file and getting the stream for each entry. I'll make the code actually recursive so you don't have to worry about the depth of the nested zip files, but as it is it should work. – xtratic Jul 12 '18 at 12:14
  • @Gordon I've reworked my code to actually include the filtering and copying. Does this not answer your question? – xtratic Jul 12 '18 at 18:42
  • It answers yes ! Thank you ! – Gordon Jul 13 '18 at 07:57