• Java压缩包解压到指定文件


        在获得一个以Zip格式压缩的文件之后,需要将其进行解压缩,还原成压缩前的文件。若是使用Java自带的压缩工具包来实现解压缩文件到指定文件夹的功能,因为jdk提供的zip只能按UTF-8格式处理,Windows系统中文件名是以GBK方式编码的,所以如果是解压一个包含中文文件名的zip,会报非法参数异常,如图所示:

        

    所以要实现解压缩,就得对DeflaterOutputStream.javaInflaterInputStream.javaZipConstants.javaZipEntry.javaZipInputStream.java以及ZipOutputStream.java这些相关的类进行修改,过程如下:

    1. 因为从 J2SE 1.4 开始,Java 编译器不再支持 import 进未命包名的类、接口,所以在创建的Java项目中,一定要新建一个自己定义的包,包命名的格式一般为学校域名的逆序+自己的网名,比如cn.edu.xidian.crytoll
    2. 在包内新建DeflaterOutputStream类,代码如下:

    DeflaterOutputStream.java:

    package cn.edu.xdian.crytoll;
    
    import java.io.FilterOutputStream;
    import java.io.IOException;
    import java.io.OutputStream;
    import java.util.zip.Deflater;
    
    /**
     * This class implements an output stream filter for compressing data in
     * the "deflate" compression format. It is also used as the basis for other
     * types of compression filters, such as GZIPOutputStream.
     *
     * @see		Deflater
     * @version 	1.36, 03/13/06
     * @author 	David Connelly
     */
    public
    class DeflaterOutputStream extends FilterOutputStream {
        /**
         * Compressor for this stream.
         */
        protected Deflater def;
    
        /**
         * Output buffer for writing compressed data.
         */
        protected byte[] buf;
       
        /**
         * Indicates that the stream has been closed.
         */
    
        private boolean closed = false;
    
        /**
         * Creates a new output stream with the specified compressor and
         * buffer size.
         * @param out the output stream
         * @param def the compressor ("deflater")
         * @param size the output buffer size
         * @exception IllegalArgumentException if size is <= 0
         */
        public DeflaterOutputStream(OutputStream out, Deflater def, int size) {
            super(out);
            if (out == null || def == null) {
                throw new NullPointerException();
            } else if (size <= 0) {
                throw new IllegalArgumentException("buffer size <= 0");
            }
            this.def = def;
            buf = new byte[size];
        }
    
        /**
         * Creates a new output stream with the specified compressor and
         * a default buffer size.
         * @param out the output stream
         * @param def the compressor ("deflater")
         */
        public DeflaterOutputStream(OutputStream out, Deflater def) {
    	this(out, def, 512);
        }
    
        boolean usesDefaultDeflater = false;
    
        /**
         * Creates a new output stream with a default compressor and buffer size.
         * @param out the output stream
         */
        public DeflaterOutputStream(OutputStream out) {
    	this(out, new Deflater());
            usesDefaultDeflater = true;
        }
    
        /**
         * Writes a byte to the compressed output stream. This method will
         * block until the byte can be written.
         * @param b the byte to be written
         * @exception IOException if an I/O error has occurred
         */
        public void write(int b) throws IOException {
            byte[] buf = new byte[1];
    	buf[0] = (byte)(b & 0xff);
    	write(buf, 0, 1);
        }
    
        /**
         * Writes an array of bytes to the compressed output stream. This
         * method will block until all the bytes are written.
         * @param b the data to be written
         * @param off the start offset of the data
         * @param len the length of the data
         * @exception IOException if an I/O error has occurred
         */
        public void write(byte[] b, int off, int len) throws IOException {
    	if (def.finished()) {
    	    throw new IOException("write beyond end of stream");
    	}
            if ((off | len | (off + len) | (b.length - (off + len))) < 0) {
    	    throw new IndexOutOfBoundsException();
    	} else if (len == 0) {
    	    return;
    	}
    	if (!def.finished()) {
                // Deflate no more than stride bytes at a time.  This avoids
                // excess copying in deflateBytes (see Deflater.c)
                int stride = buf.length;
                for (int i = 0; i < len; i+= stride) {
                    def.setInput(b, off + i, Math.min(stride, len - i));
                    while (!def.needsInput()) {
                        deflate();
                    }
                }
    	}
        }
    
        /**
         * Finishes writing compressed data to the output stream without closing
         * the underlying stream. Use this method when applying multiple filters
         * in succession to the same output stream.
         * @exception IOException if an I/O error has occurred
         */
        public void finish() throws IOException {
    	if (!def.finished()) {
    	    def.finish();
    	    while (!def.finished()) {
    		deflate();
    	    }
    	}
        }
    
        /**
         * Writes remaining compressed data to the output stream and closes the
         * underlying stream.
         * @exception IOException if an I/O error has occurred
         */
        public void close() throws IOException {
            if (!closed) {
                finish();
                if (usesDefaultDeflater)
                    def.end();
                out.close();
                closed = true;
            }
        }
    
        /**
         * Writes next block of compressed data to the output stream.
         * @throws IOException if an I/O error has occurred
         */
        protected void deflate() throws IOException {
    	int len = def.deflate(buf, 0, buf.length);
    	if (len > 0) {
    	    out.write(buf, 0, len);
    	}
        }
    }
    

      3. 在包内新建InflaterInputStream类,代码如下:

    InflaterInputStream.java:

    package cn.edu.xdian.crytoll;
    
    
    import java.io.EOFException;
    import java.io.FilterInputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.util.zip.DataFormatException;
    import java.util.zip.Inflater;
    import java.util.zip.ZipException;
    
    /**
     * This class implements a stream filter for uncompressing data in the
     * "deflate" compression format. It is also used as the basis for other
     * decompression filters, such as GZIPInputStream.
     *
     * @see		Inflater
     * @version 	1.40, 04/07/06
     * @author 	David Connelly
     */
    public
    class InflaterInputStream extends FilterInputStream {
        /**
         * Decompressor for this stream.
         */
        protected Inflater inf;
    
        /**
         * Input buffer for decompression.
         */
        protected byte[] buf;
    
        /**
         * Length of input buffer.
         */
        protected int len;
    
        private boolean closed = false;
        // this flag is set to true after EOF has reached
        private boolean reachEOF = false;
        
        /**
         * Check to make sure that this stream has not been closed
         */
        private void ensureOpen() throws IOException {
    	if (closed) {
    	    throw new IOException("Stream closed");
            }
        }
    
    
        /**
         * Creates a new input stream with the specified decompressor and
         * buffer size.
         * @param in the input stream
         * @param inf the decompressor ("inflater")
         * @param size the input buffer size
         * @exception IllegalArgumentException if size is <= 0
         */
        public InflaterInputStream(InputStream in, Inflater inf, int size) {
    	super(in);
            if (in == null || inf == null) {
                throw new NullPointerException();
            } else if (size <= 0) {
                throw new IllegalArgumentException("buffer size <= 0");
            }
    	this.inf = inf;
    	buf = new byte[size];
        }
    
        /**
         * Creates a new input stream with the specified decompressor and a
         * default buffer size.
         * @param in the input stream
         * @param inf the decompressor ("inflater")
         */
        public InflaterInputStream(InputStream in, Inflater inf) {
    	this(in, inf, 512);
        }
    
        boolean usesDefaultInflater = false;
    
        /**
         * Creates a new input stream with a default decompressor and buffer size.
         * @param in the input stream
         */
        public InflaterInputStream(InputStream in) {
    	this(in, new Inflater());
            usesDefaultInflater = true;
        }
    
        private byte[] singleByteBuf = new byte[1];
    
        /**
         * Reads a byte of uncompressed data. This method will block until
         * enough input is available for decompression.
         * @return the byte read, or -1 if end of compressed input is reached
         * @exception IOException if an I/O error has occurred
         */
        public int read() throws IOException {
    	ensureOpen();
    	return read(singleByteBuf, 0, 1) == -1 ? -1 : singleByteBuf[0] & 0xff;
        }
    
        /**
         * Reads uncompressed data into an array of bytes. If <code>len</code> is not
         * zero, the method will block until some input can be decompressed; otherwise,
         * no bytes are read and <code>0</code> is returned.
         * @param b the buffer into which the data is read
         * @param off the start offset in the destination array <code>b</code>
         * @param len the maximum number of bytes read
         * @return the actual number of bytes read, or -1 if the end of the
         *         compressed input is reached or a preset dictionary is needed
         * @exception  NullPointerException If <code>b</code> is <code>null</code>.
         * @exception  IndexOutOfBoundsException If <code>off</code> is negative, 
         * <code>len</code> is negative, or <code>len</code> is greater than 
         * <code>b.length - off</code>
         * @exception ZipException if a ZIP format error has occurred
         * @exception IOException if an I/O error has occurred
         */
        public int read(byte[] b, int off, int len) throws IOException {
    	ensureOpen();
    	if (b == null) {
    	    throw new NullPointerException();
    	} else if (off < 0 || len < 0 || len > b.length - off) {
    	    throw new IndexOutOfBoundsException();
    	} else if (len == 0) {
    	    return 0;
    	}
    	try {
    	    int n;
    	    while ((n = inf.inflate(b, off, len)) == 0) {
    		if (inf.finished() || inf.needsDictionary()) {
                        reachEOF = true;
    		    return -1;
    		}
    		if (inf.needsInput()) {
    		    fill();
    		}
    	    }
    	    return n;
    	} catch (DataFormatException e) {
    	    String s = e.getMessage();
    	    throw new ZipException(s != null ? s : "Invalid ZLIB data format");
    	}
        }
    
        /**
         * Returns 0 after EOF has been reached, otherwise always return 1.
         * <p>
         * Programs should not count on this method to return the actual number
         * of bytes that could be read without blocking.
         *
         * @return     1 before EOF and 0 after EOF.
         * @exception  IOException  if an I/O error occurs.
         * 
         */
        public int available() throws IOException {
            ensureOpen();
            if (reachEOF) {
                return 0;
            } else {
                return 1;
            }
        }
    
        private byte[] b = new byte[512];
    
        /**
         * Skips specified number of bytes of uncompressed data.
         * @param n the number of bytes to skip
         * @return the actual number of bytes skipped.
         * @exception IOException if an I/O error has occurred
         * @exception IllegalArgumentException if n < 0
         */
        public long skip(long n) throws IOException {
            if (n < 0) {
                throw new IllegalArgumentException("negative skip length");
            }
    	ensureOpen();
    	int max = (int)Math.min(n, Integer.MAX_VALUE);
    	int total = 0;
    	while (total < max) {
    	    int len = max - total;
    	    if (len > b.length) {
    		len = b.length;
    	    }
    	    len = read(b, 0, len);
    	    if (len == -1) {
                    reachEOF = true;
    		break;
    	    }
    	    total += len;
    	}
    	return total;
        }
    
        /**
         * Closes this input stream and releases any system resources associated
         * with the stream.
         * @exception IOException if an I/O error has occurred
         */
        public void close() throws IOException {
            if (!closed) {
                if (usesDefaultInflater)
                    inf.end();
    	    in.close();
                closed = true;
            }
        }
    
        /**
         * Fills input buffer with more data to decompress.
         * @exception IOException if an I/O error has occurred
         */
        protected void fill() throws IOException {
    	ensureOpen();
    	len = in.read(buf, 0, buf.length);
    	if (len == -1) {
    	    throw new EOFException("Unexpected end of ZLIB input stream");
    	}
    	inf.setInput(buf, 0, len);
        }
    
        /**
         * Tests if this input stream supports the <code>mark</code> and
         * <code>reset</code> methods. The <code>markSupported</code>
         * method of <code>InflaterInputStream</code> returns
         * <code>false</code>.
         *
         * @return  a <code>boolean</code> indicating if this stream type supports
         *          the <code>mark</code> and <code>reset</code> methods.
         * @see     java.io.InputStream#mark(int)
         * @see     java.io.InputStream#reset()
         */
        public boolean markSupported() {
            return false;
        }
     
        /**
         * Marks the current position in this input stream.
         *
         * <p> The <code>mark</code> method of <code>InflaterInputStream</code>
         * does nothing.
         *
         * @param   readlimit   the maximum limit of bytes that can be read before
         *                      the mark position becomes invalid.
         * @see     java.io.InputStream#reset()
         */
        public synchronized void mark(int readlimit) {
        }
     
        /**
         * Repositions this stream to the position at the time the
         * <code>mark</code> method was last called on this input stream.
         *
         * <p> The method <code>reset</code> for class
         * <code>InflaterInputStream</code> does nothing except throw an
         * <code>IOException</code>.
         *
         * @exception  IOException  if this method is invoked.
         * @see     java.io.InputStream#mark(int)
         * @see     java.io.IOException
         */
        public synchronized void reset() throws IOException {
            throw new IOException("mark/reset not supported");
        }
    }
    

    4. 在包中新建ZipConstants接口,代码如下:

    ZipConstants.java:

    package cn.edu.xdian.crytoll;
    interface ZipConstants {
        /*
         * Header signatures
         */
        static long LOCSIG = 0x04034b50L;	// "PK0304"
        static long EXTSIG = 0x08074b50L;	// "PK0708"
        static long CENSIG = 0x02014b50L;	// "PK0102"
        static long ENDSIG = 0x06054b50L;	// "PK0506"
    
        /*
         * Header sizes in bytes (including signatures)
         */
        static final int LOCHDR = 30;	// LOC header size
        static final int EXTHDR = 16;	// EXT header size
        static final int CENHDR = 46;	// CEN header size
        static final int ENDHDR = 22;	// END header size
    
        /*
         * Local file (LOC) header field offsets
         */
        static final int LOCVER = 4;	// version needed to extract
        static final int LOCFLG = 6;	// general purpose bit flag
        static final int LOCHOW = 8;	// compression method
        static final int LOCTIM = 10;	// modification time
        static final int LOCCRC = 14;	// uncompressed file crc-32 value
        static final int LOCSIZ = 18;	// compressed size
        static final int LOCLEN = 22;	// uncompressed size
        static final int LOCNAM = 26;	// filename length
        static final int LOCEXT = 28;	// extra field length
    
        /*
         * Extra local (EXT) header field offsets
         */
        static final int EXTCRC = 4;	// uncompressed file crc-32 value
        static final int EXTSIZ = 8;	// compressed size
        static final int EXTLEN = 12;	// uncompressed size
    
        /*
         * Central directory (CEN) header field offsets
         */
        static final int CENVEM = 4;	// version made by
        static final int CENVER = 6;	// version needed to extract
        static final int CENFLG = 8;	// encrypt, decrypt flags
        static final int CENHOW = 10;	// compression method
        static final int CENTIM = 12;	// modification time
        static final int CENCRC = 16;	// uncompressed file crc-32 value
        static final int CENSIZ = 20;	// compressed size
        static final int CENLEN = 24;	// uncompressed size
        static final int CENNAM = 28;	// filename length
        static final int CENEXT = 30;	// extra field length
        static final int CENCOM = 32;	// comment length
        static final int CENDSK = 34;	// disk number start
        static final int CENATT = 36;	// internal file attributes
        static final int CENATX = 38;	// external file attributes
        static final int CENOFF = 42;	// LOC header offset
    
        /*
         * End of central directory (END) header field offsets
         */
        static final int ENDSUB = 8;	// number of entries on this disk
        static final int ENDTOT = 10;	// total number of entries
        static final int ENDSIZ = 12;	// central directory size in bytes
        static final int ENDOFF = 16;	// offset of first CEN header
        static final int ENDCOM = 20;	// zip file comment length
    }
    
    1. 在包中新建ZipEntry类,代码如下:

    ZipEntry.java:

    package cn.edu.xdian.crytoll;
    import java.util.Date;
    
    /**
     * This class is used to represent a ZIP file entry.
     *
     * @version	1.42, 01/02/08
     * @author	David Connelly
     */
    public
    class ZipEntry implements ZipConstants, Cloneable {
        String name;	// entry name
        long time = -1;	// modification time (in DOS time)
        long crc = -1;	// crc-32 of entry data
        long size = -1;	// uncompressed size of entry data
        long csize = -1;   	// compressed size of entry data
        int method = -1;	// compression method
        byte[] extra;       // optional extra field data for entry
        String comment;     // optional comment string for entry
    
        /**
         * Compression method for uncompressed entries.
         */
        public static final int STORED = 0;
    
        /**
         * Compression method for compressed (deflated) entries.
         */
        public static final int DEFLATED = 8;
    
        static {
    	/* Zip library is loaded from System.initializeSystemClass */
    	//initIDs();
        }
    
        private static native void initIDs();
    
        /**
         * Creates a new zip entry with the specified name.
         *
         * @param name the entry name
         * @exception NullPointerException if the entry name is null
         * @exception IllegalArgumentException if the entry name is longer than
         *		  0xFFFF bytes
         */
        public ZipEntry(String name) {
    	if (name == null) {
    	    throw new NullPointerException();
    	}
    	if (name.length() > 0xFFFF) {
    	    throw new IllegalArgumentException("entry name too long");
    	}
    	this.name = name;
        }
    
        /**
         * Creates a new zip entry with fields taken from the specified
         * zip entry.
         * @param e a zip Entry object
         */
        public ZipEntry(ZipEntry e) {
    	name = e.name;
    	time = e.time;
    	crc = e.crc;
    	size = e.size;
    	csize = e.csize;
    	method = e.method;
    	extra = e.extra;
    	comment = e.comment;
        }
    
        /*
         * Creates a new zip entry for the given name with fields initialized
         * from the specified jzentry data.
         */
        ZipEntry(String name, long jzentry) {
    	this.name = name;
    	initFields(jzentry);
        }
    
        private native void initFields(long jzentry);
    
        /*
         * Creates a new zip entry with fields initialized from the specified
         * jzentry data.
         */
        ZipEntry(long jzentry) {
    	initFields(jzentry);
        }
    
        /**
         * Returns the name of the entry.
         * @return the name of the entry
         */
        public String getName() {
    	return name;
        }
    
        /**
         * Sets the modification time of the entry.
         * @param time the entry modification time in number of milliseconds
         *		   since the epoch
         * @see #getTime()
         */
        public void setTime(long time) {
    	    this.time = javaToDosTime(time);
        }
    
        /**
         * Returns the modification time of the entry, or -1 if not specified.
         * @return the modification time of the entry, or -1 if not specified
         * @see #setTime(long)
         */
        public long getTime() {
    	return time != -1 ? dosToJavaTime(time) : -1;
        }
    
        /**
         * Sets the uncompressed size of the entry data.
         * @param size the uncompressed size in bytes
         * @exception IllegalArgumentException if the specified size is less
         *		  than 0 or greater than 0xFFFFFFFF bytes
         * @see #getSize()
         */
        public void setSize(long size) {
    	if (size < 0 || size > 0xFFFFFFFFL) {
    	    throw new IllegalArgumentException("invalid entry size");
    	}
    	this.size = size;
        }
    
        /**
         * Returns the uncompressed size of the entry data, or -1 if not known.
         * @return the uncompressed size of the entry data, or -1 if not known
         * @see #setSize(long)
         */
        public long getSize() {
    	return size;
        }
    
        /**
         * Returns the size of the compressed entry data, or -1 if not known.
         * In the case of a stored entry, the compressed size will be the same
         * as the uncompressed size of the entry.
         * @return the size of the compressed entry data, or -1 if not known
         * @see #setCompressedSize(long)
         */
        public long getCompressedSize() {
    	return csize;
        }
    
        /**
         * Sets the size of the compressed entry data.
         * @param csize the compressed size to set to
         * @see #getCompressedSize()
         */
        public void setCompressedSize(long csize) {
    	this.csize = csize;
        }
    
        /**
         * Sets the CRC-32 checksum of the uncompressed entry data.
         * @param crc the CRC-32 value
         * @exception IllegalArgumentException if the specified CRC-32 value is
         *		  less than 0 or greater than 0xFFFFFFFF
         * @see #getCrc()
         */
        public void setCrc(long crc) {
    	if (crc < 0 || crc > 0xFFFFFFFFL) {
    	    throw new IllegalArgumentException("invalid entry crc-32");
    	}
    	this.crc = crc;
        }
    
        /**
         * Returns the CRC-32 checksum of the uncompressed entry data, or -1 if
         * not known.
         * @return the CRC-32 checksum of the uncompressed entry data, or -1 if
         * not known
         * @see #setCrc(long)
         */
        public long getCrc() {
    	return crc;
        }
    
        /**
         * Sets the compression method for the entry.
         * @param method the compression method, either STORED or DEFLATED
         * @exception IllegalArgumentException if the specified compression
         *		  method is invalid
         * @see #getMethod()
         */
        public void setMethod(int method) {
    	if (method != STORED && method != DEFLATED) {
    	    throw new IllegalArgumentException("invalid compression method");
    	}
    	this.method = method;
        }
    
        /**
         * Returns the compression method of the entry, or -1 if not specified.
         * @return the compression method of the entry, or -1 if not specified
         * @see #setMethod(int)
         */
        public int getMethod() {
    	return method;
        }
    
        /**
         * Sets the optional extra field data for the entry.
         * @param extra the extra field data bytes
         * @exception IllegalArgumentException if the length of the specified
         *		  extra field data is greater than 0xFFFF bytes
         * @see #getExtra()
         */
        public void setExtra(byte[] extra) {
    	if (extra != null && extra.length > 0xFFFF) {
    	    throw new IllegalArgumentException("invalid extra field length");
    	}
    	this.extra = extra;
        }
    
        /**
         * Returns the extra field data for the entry, or null if none.
         * @return the extra field data for the entry, or null if none
         * @see #setExtra(byte[])
         */
        public byte[] getExtra() {
    	return extra;
        }
    
        /**
         * Sets the optional comment string for the entry.
         * @param comment the comment string
         * @exception IllegalArgumentException if the length of the specified
         *		  comment string is greater than 0xFFFF bytes
         * @see #getComment()
         */
        public void setComment(String comment) {
    	if (comment != null && comment.length() > 0xffff/3
                        && ZipOutputStream.getUTF8Length(comment) > 0xffff) {
    	    throw new IllegalArgumentException("invalid entry comment length");
    	}
    	this.comment = comment;
        }
    
        /**
         * Returns the comment string for the entry, or null if none.
         * @return the comment string for the entry, or null if none
         * @see #setComment(String)
         */
        public String getComment() {
    	return comment;
        }
    
        /**
         * Returns true if this is a directory entry. A directory entry is
         * defined to be one whose name ends with a '/'.
         * @return true if this is a directory entry
         */
        public boolean isDirectory() {
    	return name.endsWith("/");
        }
    
        /**
         * Returns a string representation of the ZIP entry.
         */
        public String toString() {
    	return getName();
        }
    
        /*
         * Converts DOS time to Java time (number of milliseconds since epoch).
         */
        private static long dosToJavaTime(long dtime) {
    	Date d = new Date((int)(((dtime >> 25) & 0x7f) + 80),
    			  (int)(((dtime >> 21) & 0x0f) - 1),
    			  (int)((dtime >> 16) & 0x1f),
    			  (int)((dtime >> 11) & 0x1f),
    			  (int)((dtime >> 5) & 0x3f),
    			  (int)((dtime << 1) & 0x3e));
    	return d.getTime();
        }
    
        /*
         * Converts Java time to DOS time.
         */
        private static long javaToDosTime(long time) {
    	Date d = new Date(time);
    	int year = d.getYear() + 1900;
    	if (year < 1980) {
    	    return (1 << 21) | (1 << 16);
    	}
    	return (year - 1980) << 25 | (d.getMonth() + 1) << 21 |
                   d.getDate() << 16 | d.getHours() << 11 | d.getMinutes() << 5 |
                   d.getSeconds() >> 1;
        }
    
        /**
         * Returns the hash code value for this entry.
         */
        public int hashCode() {
    	return name.hashCode();
        }
    
        /**
         * Returns a copy of this entry.
         */
        public Object clone() {
    	try {
    	    ZipEntry e = (ZipEntry)super.clone();
    	    e.extra = (extra == null ? null : (byte[])extra.clone());
    	    return e;
    	} catch (CloneNotSupportedException e) {
    	    // This should never happen, since we are Cloneable
    	    throw new InternalError();
    	}
        }
    }
    

    6. 在包中新建ZipInputStream类,代码如下:

    ZipInputStream.java:

    package cn.edu.xdian.crytoll;
    import java.io.EOFException;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.PushbackInputStream;
    import java.io.UnsupportedEncodingException;
    import java.util.zip.CRC32;
    import java.util.zip.Inflater;
    import java.util.zip.ZipException;
    
    /**
     * This class implements an input stream filter for reading files in the
     * ZIP file format. Includes support for both compressed and uncompressed
     * entries.
     *
     * @author	David Connelly
     * @version	1.44, 06/15/07
     */
    public
    class ZipInputStream extends InflaterInputStream implements ZipConstants {
        private ZipEntry entry;
        private int flag;
        private CRC32 crc = new CRC32();
        private long remaining;
        private byte[] tmpbuf = new byte[512];
    
        private static final int STORED = ZipEntry.STORED;
        private static final int DEFLATED = ZipEntry.DEFLATED;
    
        private boolean closed = false;
        // this flag is set to true after EOF has reached for
        // one entry
        private boolean entryEOF = false;
    
        /**
         * Check to make sure that this stream has not been closed
         */
        private void ensureOpen() throws IOException {
    	if (closed) {
    	    throw new IOException("Stream closed");
            }
        }
    
        /**
         * Creates a new ZIP input stream.
         * @param in the actual input stream
         */
        public ZipInputStream(InputStream in) {
    	super(new PushbackInputStream(in, 512), new Inflater(true), 512);
            usesDefaultInflater = true;
            if(in == null) {
                throw new NullPointerException("in is null");
            }
        }
    
        /**
         * Reads the next ZIP file entry and positions the stream at the
         * beginning of the entry data.
         * @return the next ZIP file entry, or null if there are no more entries
         * @exception ZipException if a ZIP file error has occurred
         * @exception IOException if an I/O error has occurred
         */
        public ZipEntry getNextEntry() throws IOException {
            ensureOpen();
    	if (entry != null) {
    	    closeEntry();
    	}
    	crc.reset();
    	inf.reset();
    	if ((entry = readLOC()) == null) {
    	    return null;
    	}
    	if (entry.method == STORED) {
    	    remaining = entry.size;
    	}
            entryEOF = false;
    	return entry;
        }
    
        /**
         * Closes the current ZIP entry and positions the stream for reading the
         * next entry.
         * @exception ZipException if a ZIP file error has occurred
         * @exception IOException if an I/O error has occurred
         */
        public void closeEntry() throws IOException {
            ensureOpen();
    	while (read(tmpbuf, 0, tmpbuf.length) != -1) ;
            entryEOF = true;
        }
    
        /**
         * Returns 0 after EOF has reached for the current entry data,
         * otherwise always return 1.
         * <p>
         * Programs should not count on this method to return the actual number
         * of bytes that could be read without blocking.
         *
         * @return     1 before EOF and 0 after EOF has reached for current entry.
         * @exception  IOException  if an I/O error occurs.
         *
         */
        public int available() throws IOException {
            ensureOpen();
            if (entryEOF) {
                return 0;
            } else {
                return 1;
            }
        }
    
        /**
         * Reads from the current ZIP entry into an array of bytes.
         * If <code>len</code> is not zero, the method
         * blocks until some input is available; otherwise, no
         * bytes are read and <code>0</code> is returned.
         * @param b the buffer into which the data is read
         * @param off the start offset in the destination array <code>b</code>
         * @param len the maximum number of bytes read
         * @return the actual number of bytes read, or -1 if the end of the
         *         entry is reached
         * @exception  NullPointerException If <code>b</code> is <code>null</code>.
         * @exception  IndexOutOfBoundsException If <code>off</code> is negative,
         * <code>len</code> is negative, or <code>len</code> is greater than
         * <code>b.length - off</code>
         * @exception ZipException if a ZIP file error has occurred
         * @exception IOException if an I/O error has occurred
         */
        public int read(byte[] b, int off, int len) throws IOException {
            ensureOpen();
            if (off < 0 || len < 0 || off > b.length - len) {
    	    throw new IndexOutOfBoundsException();
    	} else if (len == 0) {
    	    return 0;
    	}
    
    	if (entry == null) {
    	    return -1;
    	}
    	switch (entry.method) {
    	case DEFLATED:
    	    len = super.read(b, off, len);
    	    if (len == -1) {
    		readEnd(entry);
                    entryEOF = true;
    		entry = null;
    	    } else {
    		crc.update(b, off, len);
    	    }
    	    return len;
    	case STORED:
    	    if (remaining <= 0) {
                    entryEOF = true;
    		entry = null;
    		return -1;
    	    }
    	    if (len > remaining) {
    		len = (int)remaining;
    	    }
    	    len = in.read(b, off, len);
    	    if (len == -1) {
    		throw new ZipException("unexpected EOF");
    	    }
    	    crc.update(b, off, len);
    	    remaining -= len;
    	    if (remaining == 0 && entry.crc != crc.getValue()) {
    		throw new ZipException(
    		    "invalid entry CRC (expected 0x" + Long.toHexString(entry.crc) +
    		    " but got 0x" + Long.toHexString(crc.getValue()) + ")");
    	    }
    	    return len;
    	default:
    	    throw new ZipException("invalid compression method");
    	}
        }
    
        /**
         * Skips specified number of bytes in the current ZIP entry.
         * @param n the number of bytes to skip
         * @return the actual number of bytes skipped
         * @exception ZipException if a ZIP file error has occurred
         * @exception IOException if an I/O error has occurred
         * @exception IllegalArgumentException if n < 0
         */
        public long skip(long n) throws IOException {
            if (n < 0) {
                throw new IllegalArgumentException("negative skip length");
            }
            ensureOpen();
    	int max = (int)Math.min(n, Integer.MAX_VALUE);
    	int total = 0;
    	while (total < max) {
    	    int len = max - total;
    	    if (len > tmpbuf.length) {
    		len = tmpbuf.length;
    	    }
    	    len = read(tmpbuf, 0, len);
    	    if (len == -1) {
                    entryEOF = true;
    		break;
    	    }
    	    total += len;
    	}
    	return total;
        }
    
        /**
         * Closes this input stream and releases any system resources associated
         * with the stream.
         * @exception IOException if an I/O error has occurred
         */
        public void close() throws IOException {
            if (!closed) {
    	    super.close();
                closed = true;
            }
        }
    
        private byte[] b = new byte[256];
    
        /*
         * Reads local file (LOC) header for next entry.
         */
        private ZipEntry readLOC() throws IOException {
    	try {
    	    readFully(tmpbuf, 0, LOCHDR);
    	} catch (EOFException e) {
    	    return null;
    	}
    	if (get32(tmpbuf, 0) != LOCSIG) {
    	    return null;
    	}
    	// get the entry name and create the ZipEntry first
    	int len = get16(tmpbuf, LOCNAM);
            int blen = b.length;
            if (len > blen) {
                do
                    blen = blen * 2;
                while (len > blen);
                b = new byte[blen];
            }
    	readFully(b, 0, len);
    	ZipEntry e = createZipEntry(getUTF8String(b, 0, len));
    	// now get the remaining fields for the entry
    	flag = get16(tmpbuf, LOCFLG);
    	if ((flag & 1) == 1) {
    	    throw new ZipException("encrypted ZIP entry not supported");
    	}
    	e.method = get16(tmpbuf, LOCHOW);
    	e.time = get32(tmpbuf, LOCTIM);
    	if ((flag & 8) == 8) {
    	    /* "Data Descriptor" present */
    	    if (e.method != DEFLATED) {
    		throw new ZipException(
    			"only DEFLATED entries can have EXT descriptor");
    	    }
    	} else {
    	    e.crc = get32(tmpbuf, LOCCRC);
    	    e.csize = get32(tmpbuf, LOCSIZ);
    	    e.size = get32(tmpbuf, LOCLEN);
    	}
    	len = get16(tmpbuf, LOCEXT);
    	if (len > 0) {
    	    byte[] bb = new byte[len];
    	    readFully(bb, 0, len);
    	    e.setExtra(bb);
    	}
    	return e;
        }
    
        /*
         * Fetches a UTF8-encoded String from the specified byte array.
         */
        private static String getUTF8String(byte[] b, int off, int len) 
        {
            
            try
            {
                String s = new String(b, off, len, "GBK");
                return s;
            }
            catch (UnsupportedEncodingException e)
            {
                e.printStackTrace();
            }
            
            //以上为新添加的解决GBK乱码的
            
            // First, count the number of characters in the sequence
            int count = 0;
            int max = off + len;
            int i = off;
            while (i < max)
            {
                int c = b[i++] & 0xff;
                switch (c >> 4)
                {
                    case 0:
                    case 1:
                    case 2:
                    case 3:
                    case 4:
                    case 5:
                    case 6:
                    case 7:
                        // 0xxxxxxx
                        count++;
                        break;
                    case 12:
                    case 13:
                        // 110xxxxx 10xxxxxx
                        if ((int) (b[i++] & 0xc0) != 0x80)
                        {
                            throw new IllegalArgumentException();
                        }
                        count++;
                        break;
                    case 14:
                        // 1110xxxx 10xxxxxx 10xxxxxx
                        if (((int) (b[i++] & 0xc0) != 0x80)
                                || ((int) (b[i++] & 0xc0) != 0x80))
                        {
                            throw new IllegalArgumentException();
                        }
                        count++;
                        break;
                    default:
                        // 10xxxxxx, 1111xxxx
                        throw new IllegalArgumentException();
                }
            }
            if (i != max)
            {
                throw new IllegalArgumentException();
            }
            // Now decode the characters...
            char[] cs = new char[count];
            i = 0;
            while (off < max)
            {
                int c = b[off++] & 0xff;
                switch (c >> 4)
                {
                    case 0:
                    case 1:
                    case 2:
                    case 3:
                    case 4:
                    case 5:
                    case 6:
                    case 7:
                        // 0xxxxxxx
                        cs[i++] = (char) c;
                        break;
                    case 12:
                    case 13:
                        // 110xxxxx 10xxxxxx
                        cs[i++] = (char) (((c & 0x1f) << 6) | (b[off++] & 0x3f));
                        break;
                    case 14:
                        // 1110xxxx 10xxxxxx 10xxxxxx
                        int t = (b[off++] & 0x3f) << 6;
                        cs[i++] = (char) (((c & 0x0f) << 12) | t | (b[off++] & 0x3f));
                        break;
                    default:
                        // 10xxxxxx, 1111xxxx
                        throw new IllegalArgumentException();
                }
            }
            return new String(cs, 0, count);
        }
    
        /**
         * Creates a new <code>ZipEntry</code> object for the specified
         * entry name.
         *
         * @param name the ZIP file entry name
         * @return the ZipEntry just created
         */
        protected ZipEntry createZipEntry(String name) {
    	return new ZipEntry(name);
        }
    
        /*
         * Reads end of deflated entry as well as EXT descriptor if present.
         */
        private void readEnd(ZipEntry e) throws IOException {
    	int n = inf.getRemaining();
    	if (n > 0) {
    	    ((PushbackInputStream)in).unread(buf, len - n, n);
    	}
    	if ((flag & 8) == 8) {
    	    /* "Data Descriptor" present */
    	    readFully(tmpbuf, 0, EXTHDR);
    	    long sig = get32(tmpbuf, 0);
                if (sig != EXTSIG) { // no EXTSIG present
                    e.crc = sig;
                    e.csize = get32(tmpbuf, EXTSIZ - EXTCRC);
                    e.size = get32(tmpbuf, EXTLEN - EXTCRC);
                    ((PushbackInputStream)in).unread(
                                               tmpbuf, EXTHDR - EXTCRC - 1, EXTCRC);
                } else {
                    e.crc = get32(tmpbuf, EXTCRC);
                    e.csize = get32(tmpbuf, EXTSIZ);
                    e.size = get32(tmpbuf, EXTLEN);
                }
    	}
    	if (e.size != inf.getBytesWritten()) {
    	    throw new ZipException(
    		"invalid entry size (expected " + e.size +
    		" but got " + inf.getBytesWritten() + " bytes)");
    	}
    	if (e.csize != inf.getBytesRead()) {
    	    throw new ZipException(
    		"invalid entry compressed size (expected " + e.csize +
    		" but got " + inf.getBytesRead() + " bytes)");
    	}
    	if (e.crc != crc.getValue()) {
    	    throw new ZipException(
    		"invalid entry CRC (expected 0x" + Long.toHexString(e.crc) +
    		" but got 0x" + Long.toHexString(crc.getValue()) + ")");
    	}
        }
    
        /*
         * Reads bytes, blocking until all bytes are read.
         */
        private void readFully(byte[] b, int off, int len) throws IOException {
    	while (len > 0) {
    	    int n = in.read(b, off, len);
    	    if (n == -1) {
    		throw new EOFException();
    	    }
    	    off += n;
    	    len -= n;
    	}
        }
    
        /*
         * Fetches unsigned 16-bit value from byte array at specified offset.
         * The bytes are assumed to be in Intel (little-endian) byte order.
         */
        private static final int get16(byte b[], int off) {
    	return (b[off] & 0xff) | ((b[off+1] & 0xff) << 8);
        }
    
        /*
         * Fetches unsigned 32-bit value from byte array at specified offset.
         * The bytes are assumed to be in Intel (little-endian) byte order.
         */
        private static final long get32(byte b[], int off) {
    	return get16(b, off) | ((long)get16(b, off+2) << 16);
        }
    }
    

    7. 在包中新建ZipOutputStream类,代码如下:

    ZipOutputStream.java:

    package cn.edu.xdian.crytoll;
    import java.io.IOException;
    import java.io.OutputStream;
    import java.util.HashSet;
    import java.util.Vector;
    import java.util.zip.CRC32;
    import java.util.zip.Deflater;
    import java.util.zip.ZipException;
    
    /**
     * 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.35, 07/31/06
     */
    public
    class ZipOutputStream extends DeflaterOutputStream implements ZipConstants {
    
        private static class XEntry {
    	public final ZipEntry entry;
    	public final long offset;
    	public final int flag;
    	public XEntry(ZipEntry entry, long offset) {
    	    this.entry = entry;
    	    this.offset = offset;
    	    this.flag = (entry.method == DEFLATED &&
    			 (entry.size  == -1 ||
    			  entry.csize == -1 ||
    			  entry.crc   == -1))
    		// store size, compressed size, and crc-32 in data descriptor
    		// immediately following the compressed entry data
    		? 8
    		// store size, compressed size, and crc-32 in LOC header
    		: 0;
    	}
        }
    
        private XEntry current;
        private Vector<XEntry> xentries = new Vector<XEntry>();
        private HashSet<String> names = new HashSet<String>();
        private CRC32 crc = new CRC32();
        private long written = 0;
        private long locoff = 0;
        private String comment;
        private int method = DEFLATED;
        private boolean finished;
    
        private boolean closed = false;
    
        private static int version(ZipEntry e) throws ZipException {
    	switch (e.method) {
    	case DEFLATED: return 20;
    	case STORED:   return 10;
    	default: throw new ZipException("unsupported compression method");
    	}
        }
    
        /**
         * Checks to make sure that this stream has not been closed.
         */
        private void ensureOpen() throws IOException {
    	if (closed) {
    	    throw new IOException("Stream closed");
            }
        }
        /**
         * Compression method for uncompressed (STORED) entries.
         */
        public static final int STORED = ZipEntry.STORED;
    
        /**
         * Compression method for compressed (DEFLATED) entries.
         */
        public static final int DEFLATED = ZipEntry.DEFLATED;
    
        /**
         * Creates a new ZIP output stream.
         * @param out the actual output stream
         */
        public ZipOutputStream(OutputStream out) {
    	super(out, new Deflater(Deflater.DEFAULT_COMPRESSION, true));
            usesDefaultDeflater = true;
        }
    
        /**
         * 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
         */
        public void setComment(String comment) {
            if (comment != null && comment.length() > 0xffff/3
                                               && getUTF8Length(comment) > 0xffff) {
    	    throw new IllegalArgumentException("ZIP file comment too long.");
    	}
    	this.comment = comment;
        }
    
        /**
         * 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
         */
        public void setMethod(int method) {
    	if (method != DEFLATED && method != STORED) {
    	    throw new IllegalArgumentException("invalid compression method");
    	}
    	this.method = method;
        }
    
        /**
         * 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
         */
        public void setLevel(int level) {
    	def.setLevel(level);
        }
    
        /**
         * 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
         */
        public void putNextEntry(ZipEntry e) throws IOException {
    	ensureOpen();
    	if (current != 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:
    	    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");
    	    }
    	    break;
    	default:
    	    throw new ZipException("unsupported compression method");
    	}
    	if (! names.add(e.name)) {
    	    throw new ZipException("duplicate entry: " + e.name);
    	}
    	current = new XEntry(e, written);
    	xentries.add(current);
            writeLOC(current);
        }
    
        /**
         * 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
         */
        public void closeEntry() throws IOException {
    	ensureOpen();
    	if (current != null) {
    	    ZipEntry e = current.entry;
    	    switch (e.method) {
    	    case DEFLATED:
    		def.finish();
    		while (!def.finished()) {
    		    deflate();
    		}
    		if ((current.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 ZipException("invalid compression method");
    	    }
    	    crc.reset();
    	    current = null;
    	}
        }
    
        /**
         * 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
         */
        public synchronized void write(byte[] b, int off, int len)
    	throws IOException
        {
    	ensureOpen();
            if (off < 0 || len < 0 || off > b.length - len) {
    	    throw new IndexOutOfBoundsException();
    	} else if (len == 0) {
    	    return;
    	}
    
    	if (current == null) {
    	    throw new ZipException("no current ZIP entry");
    	}
    	ZipEntry entry = current.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 ZipException("invalid compression method");
    	}
    	crc.update(b, off, len);
        }
    
        /**
         * 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
         */
        public void finish() throws IOException {
    	ensureOpen();
    	if (finished) {
    	    return;
    	}
    	if (current != null) {
    	    closeEntry();
    	}
    	if (xentries.size() < 1) {
    	    throw new ZipException("ZIP file must have at least one entry");
    	}
    	// write central directory
    	long off = written;
    	for (XEntry xentry : xentries)
    	    writeCEN(xentry);
    	writeEND(off, written - off);
    	finished = true;
        }
    
        /**
         * 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
         */
        public void close() throws IOException {
            if (!closed) {
                super.close();
                closed = true;
            }
        }
    
        /*
         * Writes local file (LOC) header for specified entry.
         */
        private void writeLOC(XEntry xentry) throws IOException {
    	ZipEntry e = xentry.entry;
    	int flag = xentry.flag;
    	writeInt(LOCSIG);	    // LOC header signature
    	writeShort(version(e));     // version needed to extract
    	writeShort(flag);           // general purpose bit flag
    	writeShort(e.method);       // compression method
    	writeInt(e.time);           // last modification time
    	if ((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;
        }
    
        /*
         * Writes extra data descriptor (EXT) for specified entry.
         */
        private void writeEXT(ZipEntry e) throws IOException {
    	writeInt(EXTSIG);	    // EXT header signature
    	writeInt(e.crc);	    // crc-32
    	writeInt(e.csize);	    // compressed size
    	writeInt(e.size);	    // uncompressed size
        }
    
        /*
         * Write central directory (CEN) header for specified entry.
         * REMIND: add support for file attributes
         */
        private void writeCEN(XEntry xentry) throws IOException {
    	ZipEntry e  = xentry.entry;
    	int flag = xentry.flag;
    	int version = version(e);
    	writeInt(CENSIG);	    // CEN header signature
    	writeShort(version);	    // version made by
    	writeShort(version);	    // version needed to extract
    	writeShort(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(xentry.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);
    	}
        }
    
        /*
         * Writes end of central directory (END) header.
         */
        private void writeEND(long off, long len) throws IOException {
    	int count = xentries.size();
    	writeInt(ENDSIG);	    // END record signature
    	writeShort(0);		    // number of this disk
    	writeShort(0);		    // central directory start disk
    	writeShort(count);	    // number of directory entries on disk
    	writeShort(count);	    // 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);
    	}
        }
    
        /*
         * Writes a 16-bit short to the output stream in little-endian byte order.
         */
        private void writeShort(int v) throws IOException {
    	OutputStream out = this.out;
    	out.write((v >>> 0) & 0xff);
    	out.write((v >>> 8) & 0xff);
    	written += 2;
        }
    
        /*
         * Writes a 32-bit int to the output stream in little-endian byte order.
         */
        private void writeInt(long v) throws IOException {
    	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;
        }
    
        /*
         * Writes an array of bytes to the output stream.
         */
        private void writeBytes(byte[] b, int off, int len) throws IOException {
    	super.out.write(b, off, len);
    	written += len;
        }
    
        /*
         * Returns the length of String's UTF8 encoding.
         */
        static int getUTF8Length(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;
        }
    
        /*
         * Returns an array of bytes representing the UTF8 encoding
         * of the specified String.
         */
        private static byte[] getUTF8Bytes(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;
        }
    }
    

    8. 新建一个Application Window,代码如下:

    package cn.edu.xdian.crytoll;
    import java.awt.EventQueue;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import javax.swing.JButton;
    import javax.swing.JFileChooser;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JOptionPane;
    import javax.swing.JPanel;
    import javax.swing.JScrollPane;
    import javax.swing.JSeparator;
    import javax.swing.JSpinner;
    import javax.swing.JTable;
    import javax.swing.JTextField;
    import javax.swing.border.EmptyBorder;
    import javax.swing.table.DefaultTableModel;
    
    import java.awt.GridBagLayout;
    import java.awt.GridBagConstraints;
    import java.awt.Insets;
    import java.io.File;  
    import java.io.FileInputStream;  
    import java.io.FileOutputStream;  
      
    import cn.edu.xdian.crytoll.ZipEntry;  
    import cn.edu.xdian.crytoll.ZipInputStream;  
    import cn.edu.xdian.crytoll.ZipOutputStream; 
    
    
    /**
     * 获取文件列表的过滤器
     * 
     * @author 李钟尉
     */
    public class UnZipTextFileFrame extends JFrame {
        private JPanel contentPane;
        private JTextField forderField;
        private JTextField templetField;
        private File file;
        private File dir;
        private JTable table;
        private JTextField extNameField;
        private JSpinner startSpinner;
        private JTextField textField;
        private JTextField textField_1;
        private DefaultTableModel model;
        private String filesrc;
        /**
         * Launch the application.
         */
        public static void main(String[] args) {
            EventQueue.invokeLater(new Runnable() {
                public void run() {
                    try {
                    	UnZipTextFileFrame frame = new UnZipTextFileFrame();
                        frame.setVisible(true);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            });
        }
        
        /**
         * Create the frame.
         */
        public UnZipTextFileFrame() {
            setResizable(false);
            setTitle("压缩包解压到指定文件夹");
            setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            setBounds(100, 100, 500, 300);
            getContentPane().setLayout(null);
            
            textField = new JTextField();
            textField.setBounds(10, 10, 158, 21);
            getContentPane().add(textField);
            textField.setColumns(10);
            
            JButton btnZip = new JButton("Zipu6587u4EF6");
            btnZip.addActionListener(new ActionListener() {
            	public void actionPerformed(ActionEvent e) {
            		do_btnZip_actionPerformed(e);
            	}
            });
            btnZip.setBounds(178, 9, 93, 23);
            getContentPane().add(btnZip);
            
            textField_1 = new JTextField();
            textField_1.setBounds(281, 10, 100, 21);
            getContentPane().add(textField_1);
            textField_1.setColumns(10);
            
            JButton btnNewButton = new JButton("解压到");
            btnNewButton.addActionListener(new ActionListener() {
            	public void actionPerformed(ActionEvent e) {
            		do_btnNewButton_actionPerformed(e);
            	}
            });
            btnNewButton.setBounds(391, 9, 93, 23);
            getContentPane().add(btnNewButton);
            
            JScrollPane scrollPane = new JScrollPane();
            scrollPane.setBounds(10, 41, 474, 170);
            getContentPane().add(scrollPane);
            
            table = new JTable();
            scrollPane.setViewportView(table);
            model= (DefaultTableModel) table.getModel();
            model.setColumnIdentifiers(new Object[] { "序号", "文件名"});
            JButton button = new JButton("u5F00u59CBu89E3u538Bu7F29");
            button.addActionListener(new ActionListener() {
            	public void actionPerformed(ActionEvent e) {
            		do_button_actionPerformed(e);
            	}
            });
            button.setBounds(178, 221, 100, 23);
            getContentPane().add(button);
            
        }
        protected void do_btnZip_actionPerformed(ActionEvent e){
        	JFileChooser chooser = new JFileChooser();// 创建文件选择器
            int option = chooser.showOpenDialog(this);// 显示文件打开对话框
            if (option == JFileChooser.APPROVE_OPTION) {
                file = chooser.getSelectedFile();// 获取选择的文件数组
                filesrc=file.getAbsolutePath();
                textField.setText(filesrc);// 清空文本框
            } else {
            	textField.setText("");// 清空文本框
            }
        }
        protected void do_btnNewButton_actionPerformed(ActionEvent e){
        	JFileChooser chooser = new JFileChooser();// 创建文件选择器
            // 设置选择器只针对文件夹生效
            chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
            int option = chooser.showOpenDialog(this);// 显示文件打开对话框
            if (option == JFileChooser.APPROVE_OPTION) {
                dir = chooser.getSelectedFile();// 获取选择的文件夹
                textField_1.setText(dir.toString());// 显示文件夹到文本框
            } else {
                dir = null;
                textField_1.setText("");
            }
        }
        protected void do_button_actionPerformed(ActionEvent e){
        	ZipInputStream zin;    	
        	try{
        		//filesrc=new String(filesrc.getBytes("ISO-8859-1"),"UTF-8");
        		FileInputStream in = new FileInputStream(filesrc);
        		zin=new ZipInputStream(in);
        		ZipEntry entry;
        		int i=1;
        		while(((entry=zin.getNextEntry())!=null)&&!entry.isDirectory()){
        			File file=new File(dir.toString()+"/"+entry.getName());
        			if(!file.exists()){
        				file.createNewFile();
        			}
        			zin.closeEntry();
        			Object[] property = new Object[2];
        			property[0] = i;
        			property[1] = entry.getName();
        			model.addRow(property);
        			i++;
        		}
        	}catch(Exception ex){
        		ex.printStackTrace();
        	}    	
        }
    }
    

      效果如图:

  • 相关阅读:
    form 表单提交被拦截的问题处理方法
    GitLab篇之备份还原
    GitLab篇之Linux下环境搭建
    如何管理我的开发团队
    基于静态站点内容动态推送的方案
    一个小白的程序之路(自身经历)
    敏捷开发方法学及应用
    PMBOK项目管理九大知识领域和五大流程 --美国IT项目管理硕士笔记(二)
    IT项目为什么失败 --美国IT项目管理硕士笔记(一)
    五年.net程序员Java学习之路
  • 原文地址:https://www.cnblogs.com/cysolo/p/3575466.html
Copyright © 2020-2023  润新知