FileDocCategorySizeDatePackage
ZipOutputStream.javaAPI DocJava SE 5 API15011Fri Aug 26 14:57:28 BST 2005java.util.zip

ZipOutputStream

public class ZipOutputStream extends DeflaterOutputStream implements ZipConstants
This class implements an output stream filter for writing files in the ZIP file format. Includes support for both compressed and uncompressed entries.
author
David Connelly
version
1.31, 12/19/03

Fields Summary
private ZipEntry
entry
private Vector
entries
private Hashtable
names
private CRC32
crc
private long
written
private long
locoff
private String
comment
private int
method
private boolean
finished
private boolean
closed
public static final int
STORED
Compression method for uncompressed (STORED) entries.
public static final int
DEFLATED
Compression method for compressed (DEFLATED) entries.
Constructors Summary
public ZipOutputStream(OutputStream out)
Creates a new ZIP output stream.

param
out the actual output stream


                     
       
	super(out, new Deflater(Deflater.DEFAULT_COMPRESSION, true));
        usesDefaultDeflater = true;
    
Methods Summary
public voidclose()
Closes the ZIP output stream as well as the stream being filtered.

exception
ZipException if a ZIP file error has occurred
exception
IOException if an I/O error has occurred

        if (!closed) {
            super.close();
            closed = true;
        }
    
public voidcloseEntry()
Closes the current ZIP entry and positions the stream for writing the next entry.

exception
ZipException if a ZIP format error has occurred
exception
IOException if an I/O error has occurred

	ensureOpen();
	ZipEntry e = entry;
	if (e != null) {
	    switch (e.method) {
	    case DEFLATED:
		def.finish();
		while (!def.finished()) {
		    deflate();
		}
		if ((e.flag & 8) == 0) {
		    // verify size, compressed size, and crc-32 settings
		    if (e.size != def.getBytesRead()) {
			throw new ZipException(
			    "invalid entry size (expected " + e.size +
			    " but got " + def.getBytesRead() + " bytes)");
		    }
		    if (e.csize != def.getBytesWritten()) {
			throw new ZipException(
			    "invalid entry compressed size (expected " +
			    e.csize + " but got " + def.getBytesWritten() + " bytes)");
		    }
		    if (e.crc != crc.getValue()) {
			throw new ZipException(
			    "invalid entry CRC-32 (expected 0x" +
			    Long.toHexString(e.crc) + " but got 0x" +
			    Long.toHexString(crc.getValue()) + ")");
		    }
		} else {
		    e.size  = def.getBytesRead();
		    e.csize = def.getBytesWritten();
		    e.crc = crc.getValue();
		    writeEXT(e);
		}
		def.reset();
		written += e.csize;
		break;
	    case STORED:
		// we already know that both e.size and e.csize are the same
		if (e.size != written - locoff) {
		    throw new ZipException(
			"invalid entry size (expected " + e.size +
			" but got " + (written - locoff) + " bytes)");
		}
		if (e.crc != crc.getValue()) {
		    throw new ZipException(
			 "invalid entry crc-32 (expected 0x" +
			 Long.toHexString(e.crc) + " but got 0x" +
			 Long.toHexString(crc.getValue()) + ")");
		}
		break;
	    default:
		throw new InternalError("invalid compression method");
	    }
	    crc.reset();
	    entry = null;
	}
    
private voidensureOpen()
Check to make sure that this stream has not been closed

    
                    
         
	if (closed) {
	    throw new IOException("Stream closed");
        }
    
public voidfinish()
Finishes writing the contents of the ZIP output stream without closing the underlying stream. Use this method when applying multiple filters in succession to the same output stream.

exception
ZipException if a ZIP file error has occurred
exception
IOException if an I/O exception has occurred

	ensureOpen();
	if (finished) {
	    return;
	}
	if (entry != null) {
	    closeEntry();
	}
	if (entries.size() < 1) {
	    throw new ZipException("ZIP file must have at least one entry");
	}
	// write central directory
	long off = written;
	Enumeration e = entries.elements();
	while (e.hasMoreElements()) {
	    writeCEN((ZipEntry)e.nextElement());
	}
	writeEND(off, written - off);
	finished = true;
    
private static byte[]getUTF8Bytes(java.lang.String s)

	char[] c = s.toCharArray();
	int len = c.length;
	// Count the number of encoded bytes...
	int count = 0;
	for (int i = 0; i < len; i++) {
	    int ch = c[i];
	    if (ch <= 0x7f) {
		count++;
	    } else if (ch <= 0x7ff) {
		count += 2;
	    } else {
		count += 3;
	    }
	}
	// Now return the encoded bytes...
	byte[] b = new byte[count];
	int off = 0;
	for (int i = 0; i < len; i++) {
	    int ch = c[i];
	    if (ch <= 0x7f) {
		b[off++] = (byte)ch;
	    } else if (ch <= 0x7ff) {
		b[off++] = (byte)((ch >> 6) | 0xc0);
		b[off++] = (byte)((ch & 0x3f) | 0x80);
	    } else {
		b[off++] = (byte)((ch >> 12) | 0xe0);
		b[off++] = (byte)(((ch >> 6) & 0x3f) | 0x80);
		b[off++] = (byte)((ch & 0x3f) | 0x80);
	    }
	}
	return b;
    
static intgetUTF8Length(java.lang.String s)

        int count = 0;
        for (int i = 0; i < s.length(); i++) {
            char ch = s.charAt(i); 
            if (ch <= 0x7f) {
                count++;
            } else if (ch <= 0x7ff) {
                count += 2;
            } else {
                count += 3;
            }
        }
        return count;
    
public voidputNextEntry(java.util.zip.ZipEntry e)
Begins writing a new ZIP file entry and positions the stream to the start of the entry data. Closes the current entry if still active. The default compression method will be used if no compression method was specified for the entry, and the current time will be used if the entry has no set modification time.

param
e the ZIP entry to be written
exception
ZipException if a ZIP format error has occurred
exception
IOException if an I/O error has occurred

	ensureOpen();
	if (entry != null) {
	    closeEntry();	// close previous entry
	}
	if (e.time == -1) {
	    e.setTime(System.currentTimeMillis());
	}
	if (e.method == -1) {
	    e.method = method;	// use default method
	}
	switch (e.method) {
	case DEFLATED:
	    if (e.size == -1 || e.csize == -1 || e.crc == -1) {
		// store size, compressed size, and crc-32 in data descriptor
		// immediately following the compressed entry data
		e.flag = 8;
	    } else if (e.size != -1 && e.csize != -1 && e.crc != -1) {
		// store size, compressed size, and crc-32 in LOC header
		e.flag = 0;
	    } else {
		throw new ZipException(
		    "DEFLATED entry missing size, compressed size, or crc-32");
	    }
	    e.version = 20;
	    break;
	case STORED:
	    // compressed size, uncompressed size, and crc-32 must all be
	    // set for entries using STORED compression method
	    if (e.size == -1) {
		e.size = e.csize;
	    } else if (e.csize == -1) {
		e.csize = e.size;
	    } else if (e.size != e.csize) {
		throw new ZipException(
		    "STORED entry where compressed != uncompressed size");
	    }
	    if (e.size == -1 || e.crc == -1) {
		throw new ZipException(
		    "STORED entry missing size, compressed size, or crc-32");
	    }
	    e.version = 10;
	    e.flag = 0;
	    break;
	default:
	    throw new ZipException("unsupported compression method");
	}
	e.offset = written;
	if (names.put(e.name, e) != null) {
	    throw new ZipException("duplicate entry: " + e.name);
	}
        writeLOC(e);
	entries.addElement(e);
	entry = e;
    
public voidsetComment(java.lang.String comment)
Sets the ZIP file comment.

param
comment the comment string
exception
IllegalArgumentException if the length of the specified ZIP file comment is greater than 0xFFFF bytes

        if (comment != null && comment.length() > 0xffff/3 
                                           && getUTF8Length(comment) > 0xffff) {
	    throw new IllegalArgumentException("ZIP file comment too long.");
	}
	this.comment = comment;
    
public voidsetLevel(int level)
Sets the compression level for subsequent entries which are DEFLATED. The default setting is DEFAULT_COMPRESSION.

param
level the compression level (0-9)
exception
IllegalArgumentException if the compression level is invalid

	def.setLevel(level);
    
public voidsetMethod(int method)
Sets the default compression method for subsequent entries. This default will be used whenever the compression method is not specified for an individual ZIP file entry, and is initially set to DEFLATED.

param
method the default compression method
exception
IllegalArgumentException if the specified compression method is invalid

	if (method != DEFLATED && method != STORED) {
	    throw new IllegalArgumentException("invalid compression method");
	}
	this.method = method;
    
public synchronized voidwrite(byte[] b, int off, int len)
Writes an array of bytes to the current ZIP entry data. This method will block until all the bytes are written.

param
b the data to be written
param
off the start offset in the data
param
len the number of bytes that are written
exception
ZipException if a ZIP file error has occurred
exception
IOException if an I/O error has occurred

	ensureOpen();
        if (off < 0 || len < 0 || off > b.length - len) {
	    throw new IndexOutOfBoundsException();
	} else if (len == 0) {
	    return;
	}

	if (entry == null) {
	    throw new ZipException("no current ZIP entry");
	}
	switch (entry.method) {
	case DEFLATED:
	    super.write(b, off, len);
	    break;
	case STORED:
	    written += len;
	    if (written - locoff > entry.size) {
		throw new ZipException(
		    "attempt to write past end of STORED entry");
	    }
	    out.write(b, off, len);
	    break;
	default:
	    throw new InternalError("invalid compression method");
	}
	crc.update(b, off, len);
    
private voidwriteBytes(byte[] b, int off, int len)

	super.out.write(b, off, len);
	written += len;
    
private voidwriteCEN(java.util.zip.ZipEntry e)

	writeInt(CENSIG);	    // CEN header signature
	writeShort(e.version);	    // version made by
	writeShort(e.version);	    // version needed to extract
	writeShort(e.flag);	    // general purpose bit flag
	writeShort(e.method);	    // compression method
	writeInt(e.time);	    // last modification time
	writeInt(e.crc);	    // crc-32
	writeInt(e.csize);	    // compressed size
	writeInt(e.size);	    // uncompressed size
	byte[] nameBytes = getUTF8Bytes(e.name);
	writeShort(nameBytes.length);
	writeShort(e.extra != null ? e.extra.length : 0);
	byte[] commentBytes;
	if (e.comment != null) {
	    commentBytes = getUTF8Bytes(e.comment);
	    writeShort(commentBytes.length);
	} else {
	    commentBytes = null;
	    writeShort(0);
	}
	writeShort(0);		    // starting disk number
	writeShort(0);		    // internal file attributes (unused)
	writeInt(0);		    // external file attributes (unused)
	writeInt(e.offset);	    // relative offset of local header
	writeBytes(nameBytes, 0, nameBytes.length);
	if (e.extra != null) {
	    writeBytes(e.extra, 0, e.extra.length);
	}
	if (commentBytes != null) {
	    writeBytes(commentBytes, 0, commentBytes.length);
	}
    
private voidwriteEND(long off, long len)

	writeInt(ENDSIG);	    // END record signature
	writeShort(0);		    // number of this disk
	writeShort(0);		    // central directory start disk
	writeShort(entries.size()); // number of directory entries on disk
	writeShort(entries.size()); // total number of directory entries
	writeInt(len);		    // length of central directory
	writeInt(off);		    // offset of central directory
	if (comment != null) {	    // zip file comment
	    byte[] b = getUTF8Bytes(comment);
	    writeShort(b.length);
	    writeBytes(b, 0, b.length);
	} else {
	    writeShort(0);
	}
    
private voidwriteEXT(java.util.zip.ZipEntry e)

	writeInt(EXTSIG);	    // EXT header signature
	writeInt(e.crc);	    // crc-32
	writeInt(e.csize);	    // compressed size
	writeInt(e.size);	    // uncompressed size
    
private voidwriteInt(long v)

	OutputStream out = this.out;
	out.write((int)((v >>>  0) & 0xff));
	out.write((int)((v >>>  8) & 0xff));
	out.write((int)((v >>> 16) & 0xff));
	out.write((int)((v >>> 24) & 0xff));
	written += 4;
    
private voidwriteLOC(java.util.zip.ZipEntry e)

	writeInt(LOCSIG);	    // LOC header signature
	writeShort(e.version);      // version needed to extract
	writeShort(e.flag);         // general purpose bit flag
	writeShort(e.method);       // compression method
	writeInt(e.time);           // last modification time
	if ((e.flag & 8) == 8) {
	    // store size, uncompressed size, and crc-32 in data descriptor
	    // immediately following compressed entry data
	    writeInt(0);
	    writeInt(0);
	    writeInt(0);
	} else {
	    writeInt(e.crc);        // crc-32
	    writeInt(e.csize);      // compressed size
	    writeInt(e.size);       // uncompressed size
	}
	byte[] nameBytes = getUTF8Bytes(e.name);
	writeShort(nameBytes.length);
	writeShort(e.extra != null ? e.extra.length : 0);
	writeBytes(nameBytes, 0, nameBytes.length);
	if (e.extra != null) {
	    writeBytes(e.extra, 0, e.extra.length);
	}
	locoff = written;
    
private voidwriteShort(int v)

	OutputStream out = this.out;
	out.write((v >>> 0) & 0xff);
	out.write((v >>> 8) & 0xff);
	written += 2;