今天有同学问起来用java做压缩和解压缩的程序时,出现中文问题,我以前做过,不过已经很久了,那里又没有写日志,所以也忘记了自己所做的压缩小程序,今天又重新写一编,真是很浪费时间,平时要多做笔记,以后用到时就可以顺手拿来,不然跟白学一样,一切从头再来,切记切记。
这里是用java.util.zip.ZipOutputStream来做压缩的话会出现将中文名字的文件一缩后,在压缩包里就会出现乱码的文件名,解决的办法可以修改java.util.zip.ZipOutputStream这个类,加入编码方式就可以,具体如下:
my.java.util.zip.ZipOutputStream
同时也要修改java.util.zip.ZipEntry这个类,主要是增加了三个属性:
int flag;
int version;
long offset;
在修改的ZipOutputStream类里会用到,具体ZipEntry代码如下:
my.java.util.zip.ZipEntry
有了上面那两个类后,我们就不用java.util.zip包下的这两个类来做压缩,而是用来面的修改后的类来做,我写了一个简单的测试程序如下:
解压程序我也写了,如下:
我以为用修改后的my.java.util.zip.ZipOutputStream或my.java.util.zip.ZipInputStream就可以解决问题,我将这两个类拷给同学,在他那里会出错,原来这两个类修改也包括了对它们引用到的类的修改,我现将它们打包发上来,导入就可以用了,中文名的压缩和解压缩的问题也可以解决了。
这里是用java.util.zip.ZipOutputStream来做压缩的话会出现将中文名字的文件一缩后,在压缩包里就会出现乱码的文件名,解决的办法可以修改java.util.zip.ZipOutputStream这个类,加入编码方式就可以,具体如下:
my.java.util.zip.ZipOutputStream
- /*
- *
- *
- * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
- * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
- */
- package my.java.util.zip;
- import java.io.IOException;
- import java.io.OutputStream;
- import java.util.Enumeration;
- import java.util.Hashtable;
- import java.util.Vector;
- import java.util.zip.CRC32;
- import java.util.zip.Deflater;
- import java.util.zip.ZipException;
- public class ZipOutputStream extends DeflaterOutputStream implements ZipConstants {
- private ZipEntry entry;
- private Vector entries = new Vector();
- private Hashtable names = new Hashtable();
- private CRC32 crc = new CRC32();
- private long written;
- private long locoff = 0;
- private String comment;
- private int method = DEFLATED;
- private boolean finished;
- private String encoding = "UTF-8"; // 为了支持中文,添加
- private boolean closed = false;
- /**
- * Check 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;
- }
- /**
- * Creates a new ZIP output stream.
- *
- * @param out
- * the actual output stream
- * @param encoding
- * set stream's code 为了支持中文添加
- */
- public ZipOutputStream(OutputStream out, String encoding) {
- super(out, new Deflater(Deflater.DEFAULT_COMPRESSION, true));
- usesDefaultDeflater = true;
- this.encoding = encoding;
- }
- /**
- * 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 (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;
- }
- /**
- * 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();
- ZipEntry e = entry;
- if (e != null) {
- switch (e.method) {
- case DEFLATED:
- def.finish();
- while (!def.finished()) {
- deflate();// defate意思:漏气; (使)…瘪下去
- }
- if ((e.flag & 8) == 0) {
- // verify size, compressed size, and crc-32 settings
- if (e.size != def.getTotalIn()) {
- throw new ZipException("invalid entry size (expected "
- + e.size + " but got " + def.getTotalIn()
- + " bytes)");
- }
- if (e.csize != def.getTotalOut()) {
- throw new ZipException(
- "invalid entry compressed size (expected "
- + e.csize + " but got "
- + def.getTotalOut() + " 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.getTotalIn();
- e.csize = def.getTotalOut();
- 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;
- }
- }
- /**
- * 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 (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);
- }
- /**
- * 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 (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;
- }
- /**
- * 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(ZipEntry e) throws IOException {
- 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);
- // 为了支持中文,添加 begin
- byte[] nameBytes = null;
- try {
- if (this.encoding.toUpperCase().equals("UTF-8"))
- nameBytes = getUTF8Bytes(e.name);
- else
- nameBytes = e.name.getBytes(this.encoding);
- } catch (Exception byteE) {
- nameBytes = getUTF8Bytes(e.name);
- }
- // 为了支持中文,添加 end
- 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(ZipEntry e) throws IOException {
- 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);
- // 为了支持中文,添加 begin
- byte[] nameBytes = null;
- try {
- if (this.encoding.toUpperCase().equals("UTF-8"))
- nameBytes = getUTF8Bytes(e.name);
- else
- nameBytes = e.name.getBytes(this.encoding);
- } catch (Exception byteE) {
- nameBytes = getUTF8Bytes(e.name);
- }
- // 为了支持中文,添加 end
- 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);
- }
- }
- /*
- * Writes end of central directory (END) header.
- */
- private void writeEND(long off, long len) throws IOException {
- 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);
- }
- }
- /*
- * 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;
- }
- }
同时也要修改java.util.zip.ZipEntry这个类,主要是增加了三个属性:
int flag;
int version;
long offset;
在修改的ZipOutputStream类里会用到,具体ZipEntry代码如下:
my.java.util.zip.ZipEntry
- /*
- *
- *
- * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
- * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
- */
- package my.java.util.zip;
- import java.util.Date;
- 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
- // The following flags are used only by Zip{Input,Output}Stream
- int flag; // bit flags
- int version; // version needed to extract
- long offset; // offset of loc header
- /**
- * Compression method for uncompressed entries.
- */
- public static final int STORED = 0;
- /**
- * Compression method for compressed (deflated) entries.
- */
- public static final int DEFLATED = 8;
- // static {
- // /* load the zip library */
- // java.security.AccessController.doPrivileged(
- // new sun.security.action.LoadLibraryAction("zip"));
- // //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
- */
- /**
- * 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 #setCrc(long)
- */
- 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 #getCrc()
- */
- 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();
- }
- }
- }
有了上面那两个类后,我们就不用java.util.zip包下的这两个类来做压缩,而是用来面的修改后的类来做,我写了一个简单的测试程序如下:
- package test;
- import java.io.File;
- import java.io.FileInputStream;
- import java.io.FileNotFoundException;
- import java.io.FileOutputStream;
- import java.io.IOException;
- import my.java.util.zip.ZipEntry;
- import my.java.util.zip.ZipOutputStream;
- public class zip {
- private ZipOutputStream zipOutputStream;
- private FileOutputStream fos = null;
- public zip(File in , File out)
- {
- try {
- fos = new FileOutputStream(out);
- } catch (FileNotFoundException e) {
- e.printStackTrace();
- }
- zipOutputStream = new ZipOutputStream(fos,"GBK");//只能是GBK,用UTF-8不行
- doZip(in, zipOutputStream, null);
- closeZipOutputStream();
- }
- /**
- * 用递归调用的方式将一个文件夹下的所有文件压缩进压缩包里
- * @param input 输入要压缩的文件的路径
- * @param zos 压缩输出流
- * @param relativePath 文件或文件夹在压缩包里的相对路径,一开始应将相对路径设置为null
- */
- public void doZip(File input , ZipOutputStream zos , String relativePath)
- {
- FileInputStream fis;
- byte[] b = new byte[1024];
- try {
- if(input.isDirectory())
- {
- relativePath = relativePath == null ? input.getName() : relativePath + "/" + input.getName();
- zos.putNextEntry(new ZipEntry(relativePath + "/"));//ZipEntry应该是用来设置压缩文件所存放的相对路径的,当是文件夹时一定要后面加上"/",是文件则不用加
- File[] fileList = input.listFiles();
- for(int i = 0 ; i < fileList.length ; i++)
- {
- if(fileList[i].isDirectory())
- {
- doZip(fileList[i] , zos , relativePath);
- }
- else
- {
- zos.putNextEntry(new ZipEntry(relativePath + "/" + fileList[i].getName()));//这个一定不要忘记了,不然文件是压缩不进入的哦
- fis = new FileInputStream(fileList[i]);
- while(fis.read(b) != -1)
- {
- zos.write(b);
- }
- fis.close();
- }
- }
- }
- else {
- relativePath = relativePath == null ? input.getName() : relativePath + "/" + input.getName();
- zos.putNextEntry(new ZipEntry(relativePath));//文件不用加上"/"
- fis = new FileInputStream(input);
- while(fis.read(b) != -1)
- {
- zos.write(b);
- }
- fis.close();
- }
- } catch (FileNotFoundException e) {
- e.printStackTrace();
- }catch (IOException e) {
- e.printStackTrace();
- }
- }
- //关闭输出流
- public void closeZipOutputStream()
- {
- try {
- zipOutputStream.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- //简单测试
- public static void main(String[] args)
- {
- zip test = new zip(new File("F:\\MQ") , new File("F:/MQ.zip"));
- System.out.println("压缩完成");
- }
- }
解压程序我也写了,如下:
- package test;
- import java.io.File;
- import java.io.FileInputStream;
- import java.io.FileNotFoundException;
- import java.io.FileOutputStream;
- import java.io.IOException;
- import java.util.zip.ZipException;
- import java.util.zip.ZipFile;
- import my.java.util.zip.ZipEntry;
- import my.java.util.zip.ZipInputStream;
- //解压简单例子
- public class unZip {
- File in;
- File out;
- private ZipInputStream zis;
- public unZip(File in , File out)
- {
- this.in = in;
- this.out = out;
- initial();
- }
- public void initial()
- {
- //下面是用来检查输入的文件是否是zip文件类型用的,若输入的是.rar类型也会报异常
- try {
- ZipFile zipFile = new ZipFile(in);
- zipFile.close();
- } catch (ZipException e1) {
- e1.printStackTrace();
- return ;
- } catch (IOException e1) {
- e1.printStackTrace();
- return ;
- }
- if(out == null || !out.isDirectory())
- {
- System.out.println("请选择正确的解压存放的目录!");
- return ;
- }
- try {
- zis = new ZipInputStream(new FileInputStream(in),"GBK");//支持中文的地方
- doUnZip();
- } catch (FileNotFoundException e) {
- e.printStackTrace();
- return ;
- }
- }
- public void doUnZip()
- {
- String pathName;
- ZipEntry zipEntry;
- File output;
- FileOutputStream fos;
- byte[] b;
- int len;
- String desPath;//存放的目标路径
- String tempPath;
- desPath = out.getAbsolutePath();
- try {
- zipEntry = zis.getNextEntry();//用它可以遍历在压缩包里的所有条目(包括文件和文件夹都会识别出来)
- while(zipEntry != null)
- {
- System.out.println(zipEntry.getName());
- tempPath = zipEntry.getName();
- //这里的文件路径用"\\"和"/"混合也是可以正确的创建目录或访问目录等,还是比较方便的
- if(desPath.endsWith("\\") || desPath.endsWith("/"))
- tempPath = desPath + tempPath;
- else
- tempPath = desPath + File.separator + tempPath;
- output = new File(tempPath);
- if(zipEntry.isDirectory())//这里注意啦,不是output.isDirectory()来判断,是用ZipEntry来判断
- {
- /*
- * File类的mkdir()和mkdirs()区别
- * 简单来说,mkdir()就是创建一个目录,但前提是要创建的目录的父目录一定要存在。 例如:要创建D:\myeclipseprg7\CompilerTest\WebRoot\works 这个目录,那么D:\myeclipseprg7\CompilerTest\WebRoot\这个目录就一定要存在,否则用mkdir()无法成功创建目录。如果父目录不存在,我们可以用mkdirs(),这样不管父目录是否存在,都能创建成功。这样看来,似乎mkdir()这个函数没多大用处,今后建议大家只使用mkdirs()。
- */
- output.mkdirs();
- }
- else//对于文件就直接输出
- {
- fos = new FileOutputStream(output);
- b = new byte[1024];
- while( (len = zis.read(b)) != -1)
- {
- fos.write(b, 0, len);
- }
- fos.close();
- }
- zipEntry = zis.getNextEntry();//下一条条目
- }
- } catch (IOException e) {
- e.printStackTrace();
- return;
- }
- closeZipInputStream();
- }
- public void closeZipInputStream()
- {
- try {
- zis.close();
- } catch (IOException e) {
- e.printStackTrace();
- return ;
- }
- }
- public static void main(String[] args)
- {
- unZip test = new unZip(new File("F:\\chenwenbiao.zip"), new File("F:\\"));
- }
- }
我以为用修改后的my.java.util.zip.ZipOutputStream或my.java.util.zip.ZipInputStream就可以解决问题,我将这两个类拷给同学,在他那里会出错,原来这两个类修改也包括了对它们引用到的类的修改,我现将它们打包发上来,导入就可以用了,中文名的压缩和解压缩的问题也可以解决了。