0

I have a x.zip file with the following structure (zip in zip in zip):

x.zip
     /y.zip
           /z.zip

I want to know the list of files and directories in the root of the z.zip without any unpacking archives.

nik0x1
  • 152
  • 11
  • Does this answer your question? [Read Content from Files which are inside Zip file](https://stackoverflow.com/questions/15667125/read-content-from-files-which-are-inside-zip-file) – Arsh Coder Feb 04 '23 at 12:58
  • 1
    Nope. To list files in z.zip you need access to it. Only way to do that is to unpack x.zip and y.zip – John Williams Feb 04 '23 at 14:46
  • Is it possible with a zero compression level? – nik0x1 Feb 04 '23 at 19:43

1 Answers1

0

You can read zip file contents directly from another zip entry’s InputStream. Be warned, however, that this is known to be rather slow:

import java.io.IOException;

import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;

import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipException;

import java.util.stream.Stream;

public class NestedZipReader {
    public List<String> listEntries(ZipFile zipFile,
                                    List<String> nestedZipFiles)
    throws IOException {
        if (nestedZipFiles.isEmpty()) {
            try (Stream<? extends ZipEntry> entries = zipFile.stream()) {
                return entries.map(ZipEntry::getName).toList();
            }
        } else {
            String name = nestedZipFiles.get(0);
            ZipEntry entry = zipFile.getEntry(name);
            if (entry != null) {
                try (ZipInputStream nested = new ZipInputStream(
                    zipFile.getInputStream(entry))) {

                    return listEntries(nested, nestedZipFiles, 1);
                }
            }

            throw new IllegalArgumentException("Entry not found: " + name);
        }
    }

    public List<String> listEntries(ZipInputStream zipFile,
                                    List<String> nestedZipFiles)
    throws IOException {
        return listEntries(zipFile, nestedZipFiles, 0);
    }

    private List<String> listEntries(ZipInputStream zipFile,
                                     List<String> nestedZipFiles,
                                     int nestedZipFileIndex)
    throws IOException {

        int count = nestedZipFiles.size();
        if (nestedZipFileIndex >= count) {
            List<String> names = new ArrayList<>();

            ZipEntry entry;
            while ((entry = zipFile.getNextEntry()) != null) {
                names.add(entry.getName());
            }

            return names;
        } else {
            String name = nestedZipFiles.get(nestedZipFileIndex);

            ZipEntry entry;
            while ((entry = zipFile.getNextEntry()) != null) {
                if (entry.getName().equals(name)) {
                    try (ZipInputStream nested = new ZipInputStream(zipFile)) {
                        return listEntries(
                            nested, nestedZipFiles, nestedZipFileIndex + 1);
                    }
                }
            }

            throw new IllegalArgumentException("Entry not found: "
                + String.join(" => ", 
                    nestedZipFiles.subList(0, nestedZipFileIndex + 1)));
        }
    }

    public static void main(String[] args)
    throws ZipException,
           IOException {

        NestedZipReader reader = new NestedZipReader();
        List<String> entries;

        try (ZipFile zipFile = new ZipFile(args[0])) {
            entries = reader.listEntries(zipFile,
                Arrays.asList(args).subList(1, args.length));
        }

        System.out.printf("%,d entries:%n%n", entries.size());
        for (String entry : entries) {
            System.out.println(entry);
        }
    }
}
VGR
  • 40,506
  • 4
  • 48
  • 63