UNPACKING ZIP FILES

Zip files are used widely for packaging and
distributing software.  ZipFile is a handy tool for doing the following:
reading the contents of .zip and .jar files, obtaining a list of the files
they contain, and reading the contents of individual files.  Jar files,
used in Java software distribution, employ the Zip file format as well.
For more information on Jar files, see JDC Tech Tips No.  1 (September 3,
1997) at the following address:

http://developer.javasoft.com/developer/technicalArticles/TechTips/

java.util.ZipFile is a class used to represent a Zip file.  You construct a
ZipFile object, and then iterate over the entries in the file, each of
which is a ZipEntry.  Entries can be checked to determine if they are
directories and read from as if they were individual files, in addition to
other functions.  The ZipFile class is found in both JDK 1.1 and JDK 1.2
beta2.

Here is an example of using ZipFile to dump out the entries and contents of
a .zip file.  The program accepts a single file argument, along with an
optional -contents flag that indicates the contents should also be
displayed (note that printing a binary file to screen does not work well).


        import java.io.*;
        import java.util.Enumeration;
        import java.util.zip.*;
        
        public class zipview {
                public static void dump(ZipFile zf, ZipEntry ze)
                    throws IOException
                {
                        System.out.println(">>>>> " + ze.getName());
                        InputStream istr = zf.getInputStream(ze);
                        BufferedInputStream bis =
                            new BufferedInputStream(istr);
                        FileDescriptor out = FileDescriptor.out;
                        FileOutputStream fos = new FileOutputStream(out);
                        int sz = (int)ze.getSize();
                        final int N = 1024;
                        byte buf[] = new byte[N];
                        int ln = 0;
                        while (sz > 0 &&  // workaround for bug
                            (ln = bis.read(buf, 0, Math.min(N, sz))) != -1) {
                                fos.write(buf, 0, ln);
                                sz -= ln;
                        }
                        bis.close();
                        fos.flush();
                }
        
                public static void main(String args[])
                {
                        boolean dump_contents = false;
                        int arg_indx = 0;
                        ZipFile zf = null;
        
                        if (args.length >= 1 && args[0].equals("-contents")) {
                                dump_contents = true;
                                arg_indx++;
                        }
                        if (arg_indx >= args.length) {
                                System.err.println("usage: [-contents] file");
                                System.exit(1);
                        }
        
                        try {
                                zf = new ZipFile(args[arg_indx]);
                        }
                        catch (ZipException e1) {
                                System.err.println("exception: " + e1);
                        }
                        catch (IOException e2) {
                                System.err.println("exception: " + e2);
                        }
        
                        Enumeration list = zf.entries();
                        while (list.hasMoreElements()) {
                                ZipEntry ze = (ZipEntry)list.nextElement();
                                if (!dump_contents || ze.isDirectory()) {
                                        System.out.println(ze.getName());
                                        continue;
                                }
                                try {
                                        dump(zf, ze);
                                }
                                catch (IOException e) {
                                        System.err.println("exception: " + e);
                                }
                        }
                }
        } 

This program includes a workaround for a bug in JDK versions 1.1 and 1.2
beta 2, that is, bug #4040920 in the JDC Bug Parade database.  Normally,
when you read from a low-level file input stream, you read chunks of, say,
1024 bytes at a time, and you don't worry whether that many bytes are
actually left to read.  This approach fails with the input stream returned
by getInputStream for a given Zip file entry, and the workaround is to
never try to read more bytes from the entry than are actually there.