Data Compression

The java.util.zip package contains classes you can use for data compression. In this section, we’ll talk about how to use these classes. We’ll also present two useful example programs that build on what you have just learned about streams and files.

The classes in the java.util.zip package support two widespread compression formats: GZIP and ZIP. Both of these are based on the ZLIB compression algorithm, which is discussed in RFC 1950, RFC 1951, and RFC 1952. These documents are available at http://www.faqs.org/rfcs. But you don’t need to read them unless you want to implement your own compression algorithm or otherwise extend the functionality of the java.util.zip package.

Compressing Data

The java.util.zip class provides two FilterOutputStream subclasses to write compressed data to a stream. To write compressed data in the GZIP format, simply wrap a GZIPOutputStream around an underlying stream and write to it. The following is a complete example that shows how to compress a file using the GZIP format:

//file: GZip.java
import java.io.*; 
import java.util.zip.*; 

public class GZip { 
  public static int sChunk = 8192; 

  public static void main(String[] args) { 
    if (args.length != 1) { 
      System.out.println("Usage: GZip source"); 
      return; 
    } 
    // create output stream
    String zipname = args[0] + ".gz"; 
    GZIPOutputStream zipout; 
    try { 
      FileOutputStream out = new FileOutputStream(zipname); 
      zipout = new GZIPOutputStream(out); 
    } 
    catch (IOException e) { 
      System.out.println("Couldn't create " + zipname + "."); 
      return; 
    } 
    byte[] buffer = new byte[sChunk]; 
    // compress the file
    try { 
      FileInputStream in = new FileInputStream(args[0]); 
      int length; 
      while ((length = in.read(buffer, 0, sChunk)) != -1) 
        zipout.write(buffer, 0, length); 
      in.close( ); 
    } 
    catch (IOException e) { 
      System.out.println("Couldn't compress " + args[0] + "."); 
    } 
    try { zipout.close( ); } 
    catch (IOException e) {} 
  } 
}

First we check to make sure we have a command-line argument representing a filename. Then we construct a GZIPOutputStream wrapped around a FileOutputStream representing the given filename, with the .gz suffix appended. With this in place, we open the source file. We read chunks of data from it and write them into the GZIPOutputStream. Finally, we clean up by closing our open streams.

Writing data to a ZIP file is a little more involved but still quite manageable. While a GZIP file contains only one compressed file, a ZIP file is actually a collection of files, some (or all) of which may be compressed. Each item in the ZIP file is represented by a ZipEntry object. When writing to a ZipOutputStream, you’ll need to call putNextEntry( ) before writing the data for each item. The following example shows how to create a ZipOutputStream. You’ll notice it’s just like creating a GZIPOutputStream:

ZipOutputStream zipout; 
try { 
  FileOutputStream out = new FileOutputStream("archive.zip"); 
  zipout = new ZipOutputStream(out); 
} 
catch (IOException e) {}

Let’s say we have two files we want to write into this archive. Before we begin writing, we need to call putNextEntry( ). We’ll create a simple entry with just a name. There are other fields in ZipEntry that you can set, but most of the time you won’t need to bother with them.

try { 
  ZipEntry entry = new ZipEntry("First"); 
  zipout.putNextEntry(entry); 
} 
catch (IOException e) {}

At this point, you can write the contents of the first file into the archive. When you’re ready to write the second file into the archive, simply call putNextEntry( ) again:

try { 
  ZipEntry entry = new ZipEntry("Second"); 
  zipout.putNextEntry(entry); 
} 
catch (IOException e) {}
               

Decompressing Data

To decompress data, you can use one of the two FilterInputStream subclasses provided in java.util.zip. To decompress data in the GZIP format, simply wrap a GZIPInputStream around an underlying FileInputStream and read from it. The following is a complete example that shows how to decompress a GZIP file:

//file: GUnzip.java
import java.io.*; 
import java.util.zip.*; 

public class GUnzip { 
  public static int sChunk = 8192; 
  public static void main(String[] args) { 
    if (args.length != 1) { 
      System.out.println("Usage: GUnzip source"); 
      return; 
    } 
    // create input stream
    String zipname, source; 
    if (args[0].endsWith(".gz")) { 
      zipname = args[0]; 
      source = args[0].substring(0, args[0].length( ) - 3); 
    } 
    else { 
      zipname = args[0] + ".gz"; 
      source = args[0]; 
    } 
    GZIPInputStream zipin; 
    try { 
      FileInputStream in = new FileInputStream(zipname); 
      zipin = new GZIPInputStream(in); 
    } 
    catch (IOException e) { 
      System.out.println("Couldn't open " + zipname + "."); 
      return; 
    } 
    byte[] buffer = new byte[sChunk]; 
    // decompress the file
    try { 
      FileOutputStream out = new FileOutputStream(source); 
      int length; 
      while ((length = zipin.read(buffer, 0, sChunk)) != -1) 
        out.write(buffer, 0, length); 
      out.close( ); 
    } 
    catch (IOException e) { 
      System.out.println("Couldn't decompress " + args[0] + ".");
    } 
    try { zipin.close( ); } 
    catch (IOException e) {} 
  } 
}

First we check to make sure we have a command-line argument representing a filename. If the argument ends with .gz, we figure out what the filename for the uncompressed file should be. Otherwise, we use the given argument and assume the compressed file has the .gz suffix. Then we construct a GZIPInputStream wrapped around a FileInputStream, representing the compressed file. With this in place, we open the target file. We read chunks of data from the GZIPInputStream and write them into the target file. Finally, we clean up by closing our open streams.

Again, the ZIP archive presents a little more complexity than the GZIP file. When reading from a ZipInputStream, you should call getNextEntry( ) before reading each item. When getNextEntry( ) returns null, there are no more items to read. The following example shows how to create a ZipInputStream. You’ll notice it’s just like creating a GZIPInputStream:

ZipInputStream zipin; 
try { 
  FileInputStream in = new FileInputStream("archive.zip"); 
  zipin = new ZipInputStream(in); 
} 
catch (IOException e) {}

Suppose we want to read two files from this archive. Before we begin reading, we need to call getNextEntry( ). At the least, the entry will give us a name of the item we are reading from the archive:

try { 
  ZipEntry first = zipin.getNextEntry( ); 
} 
catch (IOException e) {}

At this point, you can read the contents of the first item in the archive. When you come to the end of the item, the read( ) method will return -1. Now you can call getNextEntry( ) again to read the second item from the archive:

try { 
  ZipEntry second = zipin.getNextEntry( ); 
} 
catch (IOException e) {}

If you call getNextEntry( ) and it returns null, there are no more items, and you have reached the end of the archive.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset