ZIP files and JAR (Java Archive) files are very useful, and are heavily used in Java. 

JAR files are archive files that include a Java-specific manifest file. A manifest file is a metadata file contained within a JAR. It defines extension and package-related data.

For example, in JDK 1.5, the code for the Java class library may be found in a ZIP file src.zip (in the top level directory for the JDK installation). 

When loading a Java program (application or applet), it is more efficient to load from a ZIP or JAR file — only one file needs to be opened and read, rather than many different .class files. When downloading a set of files from the web, especially, using a ZIP or JAR file can have a considerable impact on performance.

So it stands to reason that Java contains a number of classes that are used to read and write ZIP and JAR files.  Here’s how you can do this yourself…

ZIP File Streams

Here is the hierarchy of classes that are used to process Zip files:

(Package java.util.zip)

Object
    Adler32
    CRC32
    Deflater
    Inflater
    ZipEntry
    ZipFile
CheckSum (interface)
Object
    InputStream
        FilterInputStream
            CheckedInputStream
            InflaterInputStream
                GZIPInputStream
                ZipInputStream
    OutputStream
        FilterOutputStream
            CheckedOutputStream
            DeflaterOutputStream
                GZIPOutputStream
                ZipOutputStream
Object
    Throwable
        Exception
            DataFormatException
            IOException
                ZipException

Classes ZipInputStream & ZipEntry

Using the ZIP file streams is relatively simple. Each file within the ZIP file has a header with information including the name of the file and the compression method that was used.

Using the ZipInputStream Class

You use a ZipInputStream to read a ZIP file.  Each file within the ZIP file is represented by a ZipEntry.

Here’s an example of how to read a ZIP file using ZipInputStream and ZipEntry:

package inputOutput;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.io.IOException;

import java.util.zip.ZipInputStream;
import java.util.zip.ZipEntry;
import javax.swing.JComboBox;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.UIManager;

/**
 *   Class to open a ZIP file, and display a list of files
 *   stored within it.
 *   When the user selects a ZIP file, the contents of the
 *   file (assumed to be text) are displayed in the text
 *   area.
 *
 *   @author Bryan J. Higgs, 19 September, 1999
 */
public class ReadZipFile extends JFrame
{
  /**
   *   Main entry point.
   */
  public static void main(String[] args)
  {
    try
    {
      // Set the system look and feel
      UIManager.setLookAndFeel( UIManager.getSystemLookAndFeelClassName() );
    } 
    catch (Exception ex)
    {
      // Ignore
    } 
    
    ReadZipFile frame = new ReadZipFile();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setVisible(true);
  }
  
  /**
   *   Constructor.
   */
  public ReadZipFile()
  {
    setTitle("ZIP File Reader");
      
    // Set up frame menus
    JMenuBar menuBar = new JMenuBar();
    setJMenuBar(menuBar);
    
    JMenu fileMenu = new JMenu("File");
    menuBar.add(fileMenu);
    
    JMenuItem openItem = new JMenuItem("Open");
    fileMenu.add(openItem);
    openItem.addActionListener( new OpenAction() );
    
    JMenuItem exitItem = new JMenuItem("Exit");
    fileMenu.add(exitItem);
    exitItem.addActionListener( new ActionListener()
      {
        public void actionPerformed(ActionEvent event)
        {
          System.exit(0);
        }
      }
    );
    
    // Set the size of the combo box, and
    // hook it up to its actions
    m_fileList.setEditable(false);
    m_fileList.addItem("Use File->Open to select ZIP file");
    m_fileList.addActionListener( new ActionListener()
    {
      public void actionPerformed(ActionEvent event)
      {
        String item = (String) m_fileList.getSelectedItem();
        if (item != null)
          loadZipFile(item);
      }
    }
    );
    m_fileText.setEditable(false);
    m_fileText.setBackground(Color.WHITE);
    
    add(m_fileList, BorderLayout.SOUTH);
    add(new JScrollPane(m_fileText), BorderLayout.CENTER);
    pack();
  }
  
  /**
   *   Inner class to handle open file events.
   */
  private class OpenAction implements ActionListener
  {
    public void actionPerformed(ActionEvent event)
    {
      JFileChooser chooser = new JFileChooser();
      chooser.setCurrentDirectory( new File(".") );
      TypeFileFilter filter = new TypeFileFilter(".zip");
      filter.setDescription("ZIP files");
      chooser.setFileFilter(filter);
      int ret = chooser.showOpenDialog(ReadZipFile.this);
      if (ret == JFileChooser.APPROVE_OPTION)
      {
        m_zipFileName = chooser.getSelectedFile().getPath();
        scanZipFile(m_zipFileName);
      }
    }
  }
  
  /**
   * Scans the ZIP file and populates the combo box.
   */
  public void scanZipFile(String zipFileName)
  {
    // Clean out the list, in case it's already in use.
    m_fileList.removeAllItems();
    ZipInputStream zin = null;
    ZipEntry entry = null;
    try
    {
      zin = new ZipInputStream( new FileInputStream(zipFileName) );
      while ( (entry = zin.getNextEntry()) != null )
      {
        m_fileList.addItem(entry.getName());
        zin.closeEntry();
      }
      m_zipFileName = zipFileName;
    }
    catch (IOException ioe)
    {
      ioe.printStackTrace();
    }
    finally
    {
      try
      {
        zin.close();
      } 
      catch (IOException ex)
      {
        // Ignore
      }
    }
  }
  
  /**
   *   Displays the files within the ZIP file,
   *   in the List component.
   */
  private void loadZipFile(String name)
  {
    ZipInputStream zin = null;
    ZipEntry entry = null;
    try
    {
      // Open the Zip file stream
      zin = new ZipInputStream( new FileInputStream(m_zipFileName) );
      // Scan through the entries until we find the one that matches
      while ( (entry = zin.getNextEntry()) != null)
      {
        // Does the name match?
        if (entry.getName().equals(name))
        {
          // Read the entry into the text area
          BufferedReader in = new BufferedReader( new InputStreamReader(zin) );
          String line;
          while ( (line = in.readLine()) != null)
          {
            m_fileText.append(line);
            m_fileText.append("\n");
          }
          // Be sure to show the start of the file, after loading.
          m_fileText.setCaretPosition(0);
        }
        zin.closeEntry();
      }
    }
    catch (IOException ioe)
    {
      ioe.printStackTrace();
    }
    finally
    {
      try
      {
        if (zin != null)
          zin.close();
      } 
      catch (IOException ex)
      {
        // Ignore
      }
    }
  }
  
  /////// Private data /////////
  
  private JComboBox m_fileList = new JComboBox();
  private JTextArea m_fileText = new JTextArea(30, 80);
  private String    m_zipFileName;
}

The above class uses a FileFilter for the FileChooser dialog:

package inputOutput;

import java.io.File;
import java.util.ArrayList;
import javax.swing.filechooser.FileFilter;

/**
 * Class to provide a file filter based on one or more
 * extensions (file types)
 *
 */
public class TypeFileFilter extends FileFilter
{
  /**
   * Creates a new instance of TypeFileFilter
   * for a single file type
   */
  public TypeFileFilter(String type)
  {
    addType(type);
  }

  /**
   * Adds a new file type to the filter
   */
  public void addType(String type)
  {
    if (!type.startsWith("."))
      type = "." + type;
    m_types.add(type.toLowerCase());
  }
  
  /**
   * Returns true if the file passes muster,
   * false otherwise.
   */
  public boolean accept(File file)
  {
    if (file.isDirectory())
      return true;
    String name = file.getName().toLowerCase();
    for (String type: m_types)
    {
      if (name.endsWith(type))
        return true;
    }
    return false;
  }

  /**
   * Returns a description for the file set that 
   * this file filter recognizes
   */
  public String getDescription()
  {
    return m_description;
  }
  
  /**
   * Sets a description for the file set that this
   * file filter recognizes.
   */
  public void setDescription(String description)
  {
    m_description = description;
  }
  
  ////// Private data //////
  
  // Holds the types that are to be matched.
  private ArrayList<String> m_types = new ArrayList<String>();
  private String m_description = "";
}

After you run this ReadZipFile class, and open a ZIP file, it produces something that looks like this (I opened the Java 5/1.5 src.zip file, and selected the java.lang.String class to display):

If you select a different entry in the combo box at the bottom of the frame, it will display the contents of that file (assuming it to be a text file).

Class ZipFile

Using the ZipFile Class

There is also a ZipFile class that allows you to access the ZIP file entries directly, rather than having to scan through the entire ZIP file sequentially.

It is likely that using the ZipFile class in place of the ZipInputStream class could provide better performance.

Here’s the same program as above, but with the ZipInputStream replaced by ZipFile.  It simplifies the code, and appears to improve performance — at least, on my machine:

package inputOutput;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.IOException;
import java.util.Enumeration;

import java.util.zip.ZipFile;
import java.util.zip.ZipEntry;
import javax.swing.JComboBox;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.UIManager;

/**
 *   Class to open a ZIP file, and display a list of files
 *   stored within it.
 *   When the user selects a ZIP file, the contents of the
 *   file (assumed to be text) are displayed in the text
 *   area.
 *
 *   @author Bryan J. Higgs, 19 September, 1999
 */
public class ReadZipFile2 extends JFrame
{
  /**
   *   Main entry point.
   */
  public static void main(String[] args)
  {
    try
    {
      // Set the system look and feel
      UIManager.setLookAndFeel( UIManager.getSystemLookAndFeelClassName() );
    } 
    catch (Exception ex)
    {
      // Ignore
    } 
    
    ReadZipFile2 frame = new ReadZipFile2();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setVisible(true);
  }
  
  /**
   *   Constructor.
   */
  public ReadZipFile2()
  {
    setTitle("ZIP File Reader 2");
      
    // Set up frame menus
    JMenuBar menuBar = new JMenuBar();
    setJMenuBar(menuBar);
    
    JMenu fileMenu = new JMenu("File");
    menuBar.add(fileMenu);
    
    JMenuItem openItem = new JMenuItem("Open");
    fileMenu.add(openItem);
    openItem.addActionListener( new OpenAction() );
    
    JMenuItem exitItem = new JMenuItem("Exit");
    fileMenu.add(exitItem);
    exitItem.addActionListener( new ActionListener()
      {
        public void actionPerformed(ActionEvent event)
        {
          System.exit(0);
        }
      }
    );
    
    // Set the size of the combo box, and
    // hook it up to its actions
    m_fileList.setEditable(false);
    m_fileList.addItem("Use File->Open to select ZIP file");
    m_fileList.addActionListener( new ActionListener()
    {
      public void actionPerformed(ActionEvent event)
      {
        String item = (String) m_fileList.getSelectedItem();
        if (item != null)
          loadZipFile(item);
      }
    }
    );
    m_fileText.setEditable(false);
    m_fileText.setBackground(Color.WHITE);
    
    add(m_fileList, BorderLayout.SOUTH);
    add(new JScrollPane(m_fileText), BorderLayout.CENTER);
    pack();
  }
  
  /**
   *   Inner class to handle open file events.
   */
  private class OpenAction implements ActionListener
  {
    public void actionPerformed(ActionEvent event)
    {
      JFileChooser chooser = new JFileChooser();
      chooser.setCurrentDirectory( new File(".") );
      TypeFileFilter filter = new TypeFileFilter(".zip");
      filter.setDescription("ZIP files");
      chooser.setFileFilter(filter);
      int ret = chooser.showOpenDialog(ReadZipFile2.this);
      if (ret == JFileChooser.APPROVE_OPTION)
      {
        String zipFileName = chooser.getSelectedFile().getPath();
        scanZipFile(zipFileName);
      }
    }
  }
  
  /**
   * Scans the ZIP file and populates the combo box.
   */
  public void scanZipFile(String zipFileName)
  {
    // Clean out the list, in case it's already in use.
    m_fileList.removeAllItems();
    
    ZipEntry entry = null;
    try
    {
      // Close any previous zip file that
      // might have been open.
      if (m_zipFile != null)
      {
        m_zipFile.close();
        m_zipFile = null;
      }
      // Open the new Zip file
      m_zipFile = new ZipFile(zipFileName);
      // Go through all the entries and
      // populate the fileList combo box.
      Enumeration en = m_zipFile.entries();
      while (en.hasMoreElements())
      {
        entry = (ZipEntry)en.nextElement();
        m_fileList.addItem(entry.getName());
      }
    }
    catch (IOException ioe)
    {
      ioe.printStackTrace();
    }
  }
  
  /**
   *   Displays the files within the ZIP file,
   *   in the List component.
   */
  private void loadZipFile(String name)
  {
    InputStream in = null;
    try
    {
      // Get the Zip entry from the already open ZipFile
      ZipEntry entry = m_zipFile.getEntry(name);
      if (entry != null)
      {
        // Populate the text area with the contents of the entry.
        m_fileText.setText("");
        in = m_zipFile.getInputStream(entry);
        BufferedReader reader = 
                    new BufferedReader(
                            new InputStreamReader(in));
        String line;
        while ( (line = reader.readLine()) != null )
        {
          m_fileText.append(line + "\n");
        }
      }
    }
    catch (IOException ioe)
    {
      ioe.printStackTrace();
    }
    finally
    {
      try
      {
        if (in != null)
          in.close();
      } 
      catch (IOException ex)
      {
        // Ignore
      }
    }
  }
  
  /////// Private data /////////
  
  private JComboBox m_fileList = new JComboBox();
  private JTextArea m_fileText = new JTextArea(30, 80);
  private ZipFile   m_zipFile;
}

It produces the same results as the earlier ReadZipFile program, but with better performance when opening an entry in the file.

JAR File Streams

Here is the JAR File Stream class hiearchy:

(Package java.util.jar)

Object
    Attributes
    Attributes.Name
    Manifest
    JarEntry
    JarFile
Object
    InputStream
        FilterInputStreamCheckedInputStream
            InflaterInputStream
                GZIPInputStream
                ZipInputStream
                    JarInputStream
    OutputStream
        FilterOutputStreamCheckedOutputStream
            DeflaterOutputStream
                GZIPOutputStream
                ZipOutputStream
                    JarOutputStream
Object
    Throwable
        ExceptionDataFormatExceptionIOExceptionZipException
                   JarException

Classes JarFile & JarEntry

The JAR file support is quite similar to the ZIP file support. 

To see just how similar, here is an example of the earlier ZIP program, changed to use the JarFile and JarEntry classes:

package inputOutput;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.IOException;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.Manifest;
import javax.swing.JButton;

import javax.swing.JComboBox;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.UIManager;

/**
 *   Class to open a JAR file, and display a list of files
 *   stored within it.
 *   When the user selects a JAR file, the contents of the
 *   file (assumed to be text) are displayed in the text
 *   area.
 *
 *   @author Bryan J. Higgs, 19 September, 1999
 */
public class ReadJarFile extends JFrame
{
  /**
   *   Main entry point.
   */
  public static void main(String[] args)
  {
    try
    {
      // Set the system look and feel
      UIManager.setLookAndFeel( UIManager.getSystemLookAndFeelClassName() );
    } 
    catch (Exception ex)
    {
      // Ignore
    } 
    
    ReadJarFile frame = new ReadJarFile();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setVisible(true);
  }
  
  /**
   *   Constructor.
   */
  public ReadJarFile()
  {
    setTitle("JAR File Reader");
      
    // Set up frame menus
    JMenuBar menuBar = new JMenuBar();
    setJMenuBar(menuBar);
    
    JMenu fileMenu = new JMenu("File");
    menuBar.add(fileMenu);
    
    JMenuItem openItem = new JMenuItem("Open");
    fileMenu.add(openItem);
    openItem.addActionListener( new OpenAction() );
    
    JMenuItem exitItem = new JMenuItem("Exit");
    fileMenu.add(exitItem);
    exitItem.addActionListener( new ActionListener()
      {
        public void actionPerformed(ActionEvent event)
        {
          System.exit(0);
        }
      }
    );
    
    // Set the size of the combo box, and
    // hook it up to its actions
    m_fileList.setEditable(false);
    m_fileList.addItem("Use File->Open to select JAR file");
    m_fileList.addActionListener( new ActionListener()
    {
      public void actionPerformed(ActionEvent event)
      {
        String item = (String) m_fileList.getSelectedItem();
        if (item != null)
          loadJarFile(item);
      }
    }
    );
    m_fileText.setEditable(false);
    m_fileText.setBackground(Color.WHITE);
    
    // Add a button (inside a JPanel) to the North,
    // to allow quick access to the manifest
    JPanel panel = new JPanel();
    add(panel, BorderLayout.NORTH);
    panel.add(m_manifestButton);
    m_manifestButton.addActionListener( new ActionListener()
      {
        public void actionPerformed(ActionEvent event)
        {
          loadManifest();
        }
      }
    );
    // Disable manifest button until a Jar file is loaded
    m_manifestButton.setEnabled(false);
    
    add(m_fileList, BorderLayout.SOUTH);
    add(new JScrollPane(m_fileText), BorderLayout.CENTER);
    pack();
  }
  
  /**
   *   Inner class to handle open file events.
   */
  private class OpenAction implements ActionListener
  {
    public void actionPerformed(ActionEvent event)
    {
      JFileChooser chooser = new JFileChooser();
      chooser.setCurrentDirectory( new File(".") );
      TypeFileFilter filter = new TypeFileFilter(".jar");
      filter.setDescription("JAR files");
      chooser.setFileFilter(filter);
      int ret = chooser.showOpenDialog(ReadJarFile.this);
      if (ret == JFileChooser.APPROVE_OPTION)
      {
        String jarFileName = chooser.getSelectedFile().getPath();
        scanJarFile(jarFileName);
      }
    }
  }
  
  /**
   * Scans the JAR file and populates the combo box.
   */
  public void scanJarFile(String jarFileName)
  {
    // Clean out the list, in case it's already in use.
    m_fileList.removeAllItems();
    
    JarEntry entry = null;
    try
    {
      // Close any previous zip file that
      // might have been open.
      if (m_jarFile != null)
      {
        m_jarFile.close();
        m_jarFile = null;
      }
      // Open the new Zip file
      m_jarFile = new JarFile(jarFileName);
      // Go through all the entries and
      // populate the fileList combo box.
      Enumeration en = m_jarFile.entries();
      while (en.hasMoreElements())
      {
        entry = (JarEntry)en.nextElement();
        m_fileList.addItem(entry.getName());
      }
      // Enable the Get Manifest button
      m_manifestButton.setEnabled(true);
    }
    catch (IOException ioe)
    {
      ioe.printStackTrace();
    }
  }
  
  /**
   *   Displays the files within the ZIP file,
   *   in the text area component.
   */
  private void loadJarFile(String name)
  {
    InputStream in = null;
    try
    {
      // Get the Jar entry from the already open JarFile
      JarEntry entry = m_jarFile.getJarEntry(name);
      if (entry != null)
      {
        // Populate the text area with the contents of the entry.
        m_fileText.setText("");
        in = m_jarFile.getInputStream(entry);
        BufferedReader reader = 
                    new BufferedReader(
                            new InputStreamReader(in));
        String line;
        while ( (line = reader.readLine()) != null )
        {
          m_fileText.append(line + "\n");
        }
      }
    }
    catch (IOException ioe)
    {
      ioe.printStackTrace();
    }
    finally
    {
      try
      {
        if (in != null)
          in.close();
      } 
      catch (IOException ex)
      {
        // Ignore
      }
    }
  }
  
  /**
   * Loads the manifest into the text area
   */
  private void loadManifest()
  {
    m_fileText.setText("");
    Manifest manifest;
    try
    {
      manifest = m_jarFile.getManifest();
      manifest.write(m_fileOutputStream);
    } 
    catch (IOException ex)
    {
      ex.printStackTrace();
    }
  }
  
  /////// Private data /////////
  
  private JButton   m_manifestButton = new JButton("Get Manifest");
  private JComboBox m_fileList = new JComboBox();
  private JTextArea m_fileText = new JTextArea(30, 80);
  private TextAreaOutputStream m_fileOutputStream =
                                 new TextAreaOutputStream(m_fileText);
  private JarFile   m_jarFile;
}

Note that I’m using a convenience class, TextAreaOutputStream, shown below:

/*
 * TextAreaOutputStream.java
 *
 * Created on January 24, 2008
 *
 */

package inputOutput;

import java.io.IOException;
import java.io.OutputStream;
import javax.swing.JTextArea;

/**
 * Class to act as an OutputStream for a text area
 *
 * @author Bryan Higgs
 * @version 1.0
 */
public class TextAreaOutputStream extends OutputStream
{
  /**
   * Creates a new instance of TextAreaOutputStream
   */
  public TextAreaOutputStream(JTextArea textArea)
  {
    m_textArea = textArea;
  }
  
  /**
   * Flush the output -- not useful in this case
   */
  @Override
  public void flush()
  { }

  /**
   * Close the output -- not useful in this case
   */  
  @Override
  public void close()
  { }
      
  /**
   * Required override for OutputStream
   *
   * Writes the specified byte to this output stream. 
   * The general contract for write is that one byte is written to the output stream. 
   * The byte to be written is the eight low-order bits of the argument b. 
   * The 24 high-order bits of b are ignored.
   *
   */
  @Override
  public void write(int b) throws IOException
  {
    if (b == '\r')
      return;
    
    if (b == '\n')
    {
      m_textArea.append(m_sb.toString());
      m_sb.setLength(0);
    }
    
    m_sb.append((char)b);  
  }
  
  ///// Private data //////
  
  private final StringBuilder m_sb = new StringBuilder();
  private JTextArea m_textArea;
}

I’m using one potentially convenient additional feature of the JarFile class:  the ability to obtain the Manifest file from the JAR.  So, I’ve added a small GUI feature to the above class to allow you to click a button to view the JAR file’s manifest:

Here, I ran the program, opened one of my NetBeans’s project’s JAR files, and clicked on the GetManifest button to view the Manifest.