java压缩文件,中文问题

来源:互联网 发布:淘宝返利怎么弄 编辑:程序博客网 时间:2024/06/05 09:21
今天有同学问起来用java做压缩和解压缩的程序时,出现中文问题,我以前做过,不过已经很久了,那里又没有写日志,所以也忘记了自己所做的压缩小程序,今天又重新写一编,真是很浪费时间,平时要多做笔记,以后用到时就可以顺手拿来,不然跟白学一样,一切从头再来,切记切记。
    这里是用java.util.zip.ZipOutputStream来做压缩的话会出现将中文名字的文件一缩后,在压缩包里就会出现乱码的文件名,解决的办法可以修改java.util.zip.ZipOutputStream这个类,加入编码方式就可以,具体如下:
my.java.util.zip.ZipOutputStream

Java代码  收藏代码
  1. /* 
  2.  *  
  3.  * 
  4.  * Copyright 2003 Sun Microsystems, Inc. All rights reserved. 
  5.  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. 
  6.  */  
  7. package my.java.util.zip;  
  8.   
  9. import java.io.IOException;  
  10. import java.io.OutputStream;  
  11. import java.util.Enumeration;  
  12. import java.util.Hashtable;  
  13. import java.util.Vector;  
  14. import java.util.zip.CRC32;  
  15. import java.util.zip.Deflater;  
  16. import java.util.zip.ZipException;  
  17.   
  18. public class ZipOutputStream extends DeflaterOutputStream implements ZipConstants {  
  19.     private ZipEntry entry;  
  20.     private Vector entries = new Vector();  
  21.     private Hashtable names = new Hashtable();  
  22.     private CRC32 crc = new CRC32();  
  23.     private long written;  
  24.     private long locoff = 0;  
  25.     private String comment;  
  26.     private int method = DEFLATED;  
  27.     private boolean finished;  
  28.     private String encoding = "UTF-8"// 为了支持中文,添加  
  29.   
  30.     private boolean closed = false;  
  31.   
  32.     /** 
  33.      * Check to make sure that this stream has not been closed 
  34.      */  
  35.     private void ensureOpen() throws IOException {  
  36.         if (closed) {  
  37.             throw new IOException("Stream closed");  
  38.         }  
  39.     }  
  40.   
  41.     /** 
  42.      * Compression method for uncompressed (STORED) entries. 
  43.      */  
  44.     public static final int STORED = ZipEntry.STORED;  
  45.   
  46.     /** 
  47.      * Compression method for compressed (DEFLATED) entries. 
  48.      */  
  49.     public static final int DEFLATED = ZipEntry.DEFLATED;  
  50.   
  51.     /** 
  52.      * Creates a new ZIP output stream. 
  53.      *  
  54.      * @param out 
  55.      *            the actual output stream 
  56.      */  
  57.     public ZipOutputStream(OutputStream out) {  
  58.         super(out, new Deflater(Deflater.DEFAULT_COMPRESSION, true));  
  59.         usesDefaultDeflater = true;  
  60.     }  
  61.   
  62.     /** 
  63.      * Creates a new ZIP output stream. 
  64.      *  
  65.      * @param out 
  66.      *            the actual output stream 
  67.      * @param encoding 
  68.      *            set stream's code 为了支持中文添加 
  69.      */  
  70.     public ZipOutputStream(OutputStream out, String encoding) {  
  71.         super(out, new Deflater(Deflater.DEFAULT_COMPRESSION, true));  
  72.         usesDefaultDeflater = true;  
  73.         this.encoding = encoding;  
  74.     }  
  75.   
  76.     /** 
  77.      * Sets the ZIP file comment. 
  78.      *  
  79.      * @param comment 
  80.      *            the comment string 
  81.      * @exception IllegalArgumentException 
  82.      *                if the length of the specified ZIP file comment is greater 
  83.      *                than 0xFFFF bytes 
  84.      */  
  85.     public void setComment(String comment) {  
  86.         if (comment != null && comment.length() > 0xffff / 3  
  87.                 && getUTF8Length(comment) > 0xffff) {  
  88.             throw new IllegalArgumentException("ZIP file comment too long.");  
  89.         }  
  90.         this.comment = comment;  
  91.     }  
  92.   
  93.     /** 
  94.      * Sets the default compression method for subsequent entries. This default 
  95.      * will be used whenever the compression method is not specified for an 
  96.      * individual ZIP file entry, and is initially set to DEFLATED. 
  97.      *  
  98.      * @param method 
  99.      *            the default compression method 
  100.      * @exception IllegalArgumentException 
  101.      *                if the specified compression method is invalid 
  102.      */  
  103.     public void setMethod(int method) {  
  104.         if (method != DEFLATED && method != STORED) {  
  105.             throw new IllegalArgumentException("invalid compression method");  
  106.         }  
  107.         this.method = method;  
  108.     }  
  109.   
  110.     /** 
  111.      * Sets the compression level for subsequent entries which are DEFLATED. The 
  112.      * default setting is DEFAULT_COMPRESSION. 
  113.      *  
  114.      * @param level 
  115.      *            the compression level (0-9) 
  116.      * @exception IllegalArgumentException 
  117.      *                if the compression level is invalid 
  118.      */  
  119.     public void setLevel(int level) {  
  120.         def.setLevel(level);  
  121.     }  
  122.   
  123.     /** 
  124.      * Begins writing a new ZIP file entry and positions the stream to the start 
  125.      * of the entry data. Closes the current entry if still active. The default 
  126.      * compression method will be used if no compression method was specified 
  127.      * for the entry, and the current time will be used if the entry has no set 
  128.      * modification time. 
  129.      *  
  130.      * @param e 
  131.      *            the ZIP entry to be written 
  132.      * @exception ZipException 
  133.      *                if a ZIP format error has occurred 
  134.      * @exception IOException 
  135.      *                if an I/O error has occurred 
  136.      */  
  137.     public void putNextEntry(ZipEntry e) throws IOException {  
  138.         ensureOpen();  
  139.         if (entry != null) {  
  140.             closeEntry(); // close previous entry  
  141.         }  
  142.         if (e.time == -1) {  
  143.             e.setTime(System.currentTimeMillis());  
  144.         }  
  145.         if (e.method == -1) {  
  146.             e.method = method; // use default method  
  147.         }  
  148.         switch (e.method) {  
  149.         case DEFLATED:  
  150.             if (e.size == -1 || e.csize == -1 || e.crc == -1) {  
  151.                 // store size, compressed size, and crc-32 in data descriptor  
  152.                 // immediately following the compressed entry data  
  153.                 e.flag = 8;  
  154.             } else if (e.size != -1 && e.csize != -1 && e.crc != -1) {  
  155.                 // store size, compressed size, and crc-32 in LOC header  
  156.                 e.flag = 0;  
  157.             } else {  
  158.                 throw new ZipException(  
  159.                         "DEFLATED entry missing size, compressed size, or crc-32");  
  160.             }  
  161.             e.version = 20;  
  162.             break;  
  163.         case STORED:  
  164.             // compressed size, uncompressed size, and crc-32 must all be  
  165.             // set for entries using STORED compression method  
  166.             if (e.size == -1) {  
  167.                 e.size = e.csize;  
  168.             } else if (e.csize == -1) {  
  169.                 e.csize = e.size;  
  170.             } else if (e.size != e.csize) {  
  171.                 throw new ZipException(  
  172.                         "STORED entry where compressed != uncompressed size");  
  173.             }  
  174.             if (e.size == -1 || e.crc == -1) {  
  175.                 throw new ZipException(  
  176.                         "STORED entry missing size, compressed size, or crc-32");  
  177.             }  
  178.             e.version = 10;  
  179.             e.flag = 0;  
  180.             break;  
  181.         default:  
  182.             throw new ZipException("unsupported compression method");  
  183.         }  
  184.         e.offset = written;  
  185.         if (names.put(e.name, e) != null) {  
  186.             throw new ZipException("duplicate entry: " + e.name);  
  187.         }  
  188.         writeLOC(e);  
  189.         entries.addElement(e);  
  190.         entry = e;  
  191.     }  
  192.   
  193.     /** 
  194.      * Closes the current ZIP entry and positions the stream for writing the 
  195.      * next entry. 
  196.      *  
  197.      * @exception ZipException 
  198.      *                if a ZIP format error has occurred 
  199.      * @exception IOException 
  200.      *                if an I/O error has occurred 
  201.      */  
  202.     public void closeEntry() throws IOException {  
  203.         ensureOpen();  
  204.         ZipEntry e = entry;  
  205.         if (e != null) {  
  206.             switch (e.method) {  
  207.             case DEFLATED:  
  208.                 def.finish();  
  209.                 while (!def.finished()) {  
  210.                     deflate();// defate意思:漏气; (使)…瘪下去  
  211.                 }  
  212.                 if ((e.flag & 8) == 0) {  
  213.                     // verify size, compressed size, and crc-32 settings  
  214.                     if (e.size != def.getTotalIn()) {  
  215.                         throw new ZipException("invalid entry size (expected "  
  216.                                 + e.size + " but got " + def.getTotalIn()  
  217.                                 + " bytes)");  
  218.                     }  
  219.                     if (e.csize != def.getTotalOut()) {  
  220.                         throw new ZipException(  
  221.                                 "invalid entry compressed size (expected "  
  222.                                         + e.csize + " but got "  
  223.                                         + def.getTotalOut() + " bytes)");  
  224.                     }  
  225.                     if (e.crc != crc.getValue()) {  
  226.                         throw new ZipException(  
  227.                                 "invalid entry CRC-32 (expected 0x"  
  228.                                         + Long.toHexString(e.crc)  
  229.                                         + " but got 0x"  
  230.                                         + Long.toHexString(crc.getValue())  
  231.                                         + ")");  
  232.                     }  
  233.                 } else {  
  234.                     e.size = def.getTotalIn();  
  235.                     e.csize = def.getTotalOut();  
  236.                     e.crc = crc.getValue();  
  237.                     writeEXT(e);  
  238.                 }  
  239.                 def.reset();  
  240.                 written += e.csize;  
  241.                 break;  
  242.             case STORED:  
  243.                 // we already know that both e.size and e.csize are the same  
  244.                 if (e.size != written - locoff) {  
  245.                     throw new ZipException("invalid entry size (expected "  
  246.                             + e.size + " but got " + (written - locoff)  
  247.                             + " bytes)");  
  248.                 }  
  249.                 if (e.crc != crc.getValue()) {  
  250.                     throw new ZipException("invalid entry crc-32 (expected 0x"  
  251.                             + Long.toHexString(e.crc) + " but got 0x"  
  252.                             + Long.toHexString(crc.getValue()) + ")");  
  253.                 }  
  254.                 break;  
  255.             default:  
  256.                 throw new InternalError("invalid compression method");  
  257.             }  
  258.             crc.reset();  
  259.             entry = null;  
  260.         }  
  261.     }  
  262.   
  263.     /** 
  264.      * Writes an array of bytes to the current ZIP entry data. This method will 
  265.      * block until all the bytes are written. 
  266.      *  
  267.      * @param b 
  268.      *            the data to be written 
  269.      * @param off 
  270.      *            the start offset in the data 
  271.      * @param len 
  272.      *            the number of bytes that are written 
  273.      * @exception ZipException 
  274.      *                if a ZIP file error has occurred 
  275.      * @exception IOException 
  276.      *                if an I/O error has occurred 
  277.      */  
  278.     public synchronized void write(byte[] b, int off, int len)throws IOException {  
  279.         ensureOpen();  
  280.         if (off < 0 || len < 0 || off > b.length - len) {  
  281.             throw new IndexOutOfBoundsException();  
  282.         } else if (len == 0) {  
  283.             return;  
  284.         }  
  285.   
  286.         if (entry == null) {  
  287.             throw new ZipException("no current ZIP entry");  
  288.         }  
  289.         switch (entry.method) {  
  290.         case DEFLATED:  
  291.             super.write(b, off, len);  
  292.             break;  
  293.         case STORED:  
  294.             written += len;  
  295.             if (written - locoff > entry.size) {  
  296.                 throw new ZipException(  
  297.                         "attempt to write past end of STORED entry");  
  298.             }  
  299.             out.write(b, off, len);  
  300.             break;  
  301.         default:  
  302.             throw new InternalError("invalid compression method");  
  303.         }  
  304.         crc.update(b, off, len);  
  305.     }  
  306.   
  307.     /** 
  308.      * Finishes writing the contents of the ZIP output stream without closing 
  309.      * the underlying stream. Use this method when applying multiple filters in 
  310.      * succession to the same output stream. 
  311.      *  
  312.      * @exception ZipException 
  313.      *                if a ZIP file error has occurred 
  314.      * @exception IOException 
  315.      *                if an I/O exception has occurred 
  316.      */  
  317.     public void finish() throws IOException {  
  318.         ensureOpen();  
  319.         if (finished) {  
  320.             return;  
  321.         }  
  322.         if (entry != null) {  
  323.             closeEntry();  
  324.         }  
  325.         if (entries.size() < 1) {  
  326.             throw new ZipException("ZIP file must have at least one entry");  
  327.         }  
  328.         // write central directory  
  329.         long off = written;  
  330.         Enumeration e = entries.elements();  
  331.         while (e.hasMoreElements()) {  
  332.             writeCEN((ZipEntry) e.nextElement());  
  333.         }  
  334.         writeEND(off, written - off);  
  335.         finished = true;  
  336.     }  
  337.   
  338.     /** 
  339.      * Closes the ZIP output stream as well as the stream being filtered. 
  340.      *  
  341.      * @exception ZipException 
  342.      *                if a ZIP file error has occurred 
  343.      * @exception IOException 
  344.      *                if an I/O error has occurred 
  345.      */  
  346.     public void close() throws IOException {  
  347.         if (!closed) {  
  348.             super.close();  
  349.             closed = true;  
  350.         }  
  351.     }  
  352.   
  353.     /* 
  354.      * Writes local file (LOC) header for specified entry. 
  355.      */  
  356.     private void writeLOC(ZipEntry e) throws IOException {  
  357.         writeInt(LOCSIG); // LOC header signature  
  358.         writeShort(e.version); // version needed to extract  
  359.         writeShort(e.flag); // general purpose bit flag  
  360.         writeShort(e.method); // compression method  
  361.         writeInt(e.time); // last modification time  
  362.         if ((e.flag & 8) == 8) {  
  363.             // store size, uncompressed size, and crc-32 in data descriptor  
  364.             // immediately following compressed entry data  
  365.             writeInt(0);  
  366.             writeInt(0);  
  367.             writeInt(0);  
  368.         } else {  
  369.             writeInt(e.crc); // crc-32  
  370.             writeInt(e.csize); // compressed size  
  371.             writeInt(e.size); // uncompressed size  
  372.         }  
  373.         // 为了支持中文,注释  
  374.         // byte[] nameBytes = getUTF8Bytes(e.name);  
  375.         // 为了支持中文,添加 begin  
  376.         byte[] nameBytes = null;  
  377.         try {  
  378.             if (this.encoding.toUpperCase().equals("UTF-8"))  
  379.                 nameBytes = getUTF8Bytes(e.name);  
  380.             else  
  381.                 nameBytes = e.name.getBytes(this.encoding);  
  382.         } catch (Exception byteE) {  
  383.             nameBytes = getUTF8Bytes(e.name);  
  384.         }  
  385.         // 为了支持中文,添加 end  
  386.         writeShort(nameBytes.length);  
  387.         writeShort(e.extra != null ? e.extra.length : 0);  
  388.         writeBytes(nameBytes, 0, nameBytes.length);  
  389.         if (e.extra != null) {  
  390.             writeBytes(e.extra, 0, e.extra.length);  
  391.         }  
  392.         locoff = written;  
  393.     }  
  394.   
  395.     /* 
  396.      * Writes extra data descriptor (EXT) for specified entry. 
  397.      */  
  398.     private void writeEXT(ZipEntry e) throws IOException {  
  399.         writeInt(EXTSIG); // EXT header signature  
  400.         writeInt(e.crc); // crc-32  
  401.         writeInt(e.csize); // compressed size  
  402.         writeInt(e.size); // uncompressed size  
  403.     }  
  404.   
  405.     /* 
  406.      * Write central directory (CEN) header for specified entry. REMIND: add 
  407.      * support for file attributes 
  408.      */  
  409.     private void writeCEN(ZipEntry e) throws IOException {  
  410.         writeInt(CENSIG); // CEN header signature  
  411.         writeShort(e.version); // version made by  
  412.         writeShort(e.version); // version needed to extract  
  413.         writeShort(e.flag); // general purpose bit flag  
  414.         writeShort(e.method); // compression method  
  415.         writeInt(e.time); // last modification time  
  416.         writeInt(e.crc); // crc-32  
  417.         writeInt(e.csize); // compressed size  
  418.         writeInt(e.size); // uncompressed size  
  419.         // 为了支持中文,注释  
  420.         // byte[] nameBytes = getUTF8Bytes(e.name);  
  421.         // 为了支持中文,添加 begin  
  422.         byte[] nameBytes = null;  
  423.         try {  
  424.             if (this.encoding.toUpperCase().equals("UTF-8"))  
  425.                 nameBytes = getUTF8Bytes(e.name);  
  426.             else  
  427.                 nameBytes = e.name.getBytes(this.encoding);  
  428.         } catch (Exception byteE) {  
  429.             nameBytes = getUTF8Bytes(e.name);  
  430.         }  
  431.         // 为了支持中文,添加 end  
  432.         writeShort(nameBytes.length);  
  433.         writeShort(e.extra != null ? e.extra.length : 0);  
  434.         byte[] commentBytes;  
  435.         if (e.comment != null) {  
  436.             commentBytes = getUTF8Bytes(e.comment);  
  437.             writeShort(commentBytes.length);  
  438.         } else {  
  439.             commentBytes = null;  
  440.             writeShort(0);  
  441.         }  
  442.         writeShort(0); // starting disk number  
  443.         writeShort(0); // internal file attributes (unused)  
  444.         writeInt(0); // external file attributes (unused)  
  445.         writeInt(e.offset); // relative offset of local header  
  446.         writeBytes(nameBytes, 0, nameBytes.length);  
  447.         if (e.extra != null) {  
  448.             writeBytes(e.extra, 0, e.extra.length);  
  449.         }  
  450.         if (commentBytes != null) {  
  451.             writeBytes(commentBytes, 0, commentBytes.length);  
  452.         }  
  453.     }  
  454.   
  455.     /* 
  456.      * Writes end of central directory (END) header. 
  457.      */  
  458.     private void writeEND(long off, long len) throws IOException {  
  459.         writeInt(ENDSIG); // END record signature  
  460.         writeShort(0); // number of this disk  
  461.         writeShort(0); // central directory start disk  
  462.         writeShort(entries.size()); // number of directory entries on disk  
  463.         writeShort(entries.size()); // total number of directory entries  
  464.         writeInt(len); // length of central directory  
  465.         writeInt(off); // offset of central directory  
  466.         if (comment != null) { // zip file comment  
  467.             byte[] b = getUTF8Bytes(comment);  
  468.             writeShort(b.length);  
  469.             writeBytes(b, 0, b.length);  
  470.         } else {  
  471.             writeShort(0);  
  472.         }  
  473.     }  
  474.   
  475.     /* 
  476.      * Writes a 16-bit short to the output stream in little-endian byte order. 
  477.      */  
  478.     private void writeShort(int v) throws IOException {  
  479.         OutputStream out = this.out;  
  480.         out.write((v >>> 0) & 0xff);  
  481.         out.write((v >>> 8) & 0xff);  
  482.         written += 2;  
  483.     }  
  484.   
  485.     /* 
  486.      * Writes a 32-bit int to the output stream in little-endian byte order. 
  487.      */  
  488.     private void writeInt(long v) throws IOException {  
  489.         OutputStream out = this.out;  
  490.         out.write((int) ((v >>> 0) & 0xff));  
  491.         out.write((int) ((v >>> 8) & 0xff));  
  492.         out.write((int) ((v >>> 16) & 0xff));  
  493.         out.write((int) ((v >>> 24) & 0xff));  
  494.         written += 4;  
  495.     }  
  496.   
  497.     /* 
  498.      * Writes an array of bytes to the output stream. 
  499.      */  
  500.     private void writeBytes(byte[] b, int off, int len) throws IOException {  
  501.         super.out.write(b, off, len);  
  502.         written += len;  
  503.     }  
  504.   
  505.     /* 
  506.      * Returns the length of String's UTF8 encoding. 
  507.      */  
  508.     static int getUTF8Length(String s) {  
  509.         int count = 0;  
  510.         for (int i = 0; i < s.length(); i++) {  
  511.             char ch = s.charAt(i);  
  512.             if (ch <= 0x7f) {  
  513.                 count++;  
  514.             } else if (ch <= 0x7ff) {  
  515.                 count += 2;  
  516.             } else {  
  517.                 count += 3;  
  518.             }  
  519.         }  
  520.         return count;  
  521.     }  
  522.   
  523.     /* 
  524.      * Returns an array of bytes representing the UTF8 encoding of the specified 
  525.      * String. 
  526.      */  
  527.     private static byte[] getUTF8Bytes(String s) {  
  528.         char[] c = s.toCharArray();  
  529.         int len = c.length;  
  530.         // Count the number of encoded bytes...  
  531.         int count = 0;  
  532.         for (int i = 0; i < len; i++) {  
  533.             int ch = c[i];  
  534.             if (ch <= 0x7f) {  
  535.                 count++;  
  536.             } else if (ch <= 0x7ff) {  
  537.                 count += 2;  
  538.             } else {  
  539.                 count += 3;  
  540.             }  
  541.         }  
  542.         // Now return the encoded bytes...  
  543.         byte[] b = new byte[count];  
  544.         int off = 0;  
  545.         for (int i = 0; i < len; i++) {  
  546.             int ch = c[i];  
  547.             if (ch <= 0x7f) {  
  548.                 b[off++] = (byte) ch;  
  549.             } else if (ch <= 0x7ff) {  
  550.                 b[off++] = (byte) ((ch >> 6) | 0xc0);  
  551.                 b[off++] = (byte) ((ch & 0x3f) | 0x80);  
  552.             } else {  
  553.                 b[off++] = (byte) ((ch >> 12) | 0xe0);  
  554.                 b[off++] = (byte) (((ch >> 6) & 0x3f) | 0x80);  
  555.                 b[off++] = (byte) ((ch & 0x3f) | 0x80);  
  556.             }  
  557.         }  
  558.         return b;  
  559.     }  
  560. }  

同时也要修改java.util.zip.ZipEntry这个类,主要是增加了三个属性:
int flag;
int version;
long offset;
在修改的ZipOutputStream类里会用到,具体ZipEntry代码如下:
my.java.util.zip.ZipEntry
Java代码  收藏代码
  1. /* 
  2.  *  
  3.  * 
  4.  * Copyright 2003 Sun Microsystems, Inc. All rights reserved. 
  5.  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. 
  6.  */  
  7. package my.java.util.zip;  
  8.   
  9. import java.util.Date;  
  10.   
  11. public class ZipEntry implements ZipConstants, Cloneable {  
  12.     String name; // entry name  
  13.     long time = -1// modification time (in DOS time)  
  14.     long crc = -1// crc-32 of entry data  
  15.     long size = -1// uncompressed size of entry data  
  16.     long csize = -1// compressed size of entry data  
  17.     int method = -1// compression method  
  18.     byte[] extra; // optional extra field data for entry  
  19.     String comment; // optional comment string for entry  
  20.     // The following flags are used only by Zip{Input,Output}Stream  
  21.     int flag; // bit flags  
  22.     int version; // version needed to extract  
  23.     long offset; // offset of loc header  
  24.   
  25.     /** 
  26.      * Compression method for uncompressed entries. 
  27.      */  
  28.     public static final int STORED = 0;  
  29.   
  30.     /** 
  31.      * Compression method for compressed (deflated) entries. 
  32.      */  
  33.     public static final int DEFLATED = 8;  
  34.   
  35.     // static {  
  36.     // /* load the zip library */  
  37.     // java.security.AccessController.doPrivileged(  
  38.     // new sun.security.action.LoadLibraryAction("zip"));  
  39.     // //initIDs();  
  40.     // }  
  41.   
  42.     private static native void initIDs();  
  43.   
  44.     /** 
  45.      * Creates a new zip entry with the specified name. 
  46.      *  
  47.      * @param name 
  48.      *            the entry name 
  49.      * @exception NullPointerException 
  50.      *                if the entry name is null 
  51.      * @exception IllegalArgumentException 
  52.      *                if the entry name is longer than 0xFFFF bytes 
  53.      */  
  54.     public ZipEntry(String name) {  
  55.         if (name == null) {  
  56.             throw new NullPointerException();  
  57.         }  
  58.         if (name.length() > 0xFFFF) {  
  59.             throw new IllegalArgumentException("entry name too long");  
  60.         }  
  61.         this.name = name;  
  62.     }  
  63.   
  64.     /** 
  65.      * Creates a new zip entry with fields taken from the specified zip entry. 
  66.      *  
  67.      * @param e 
  68.      *            a zip Entry object 
  69.      */  
  70.   
  71.     /** 
  72.      * Returns the name of the entry. 
  73.      *  
  74.      * @return the name of the entry 
  75.      */  
  76.     public String getName() {  
  77.         return name;  
  78.     }  
  79.   
  80.     /** 
  81.      * Sets the modification time of the entry. 
  82.      *  
  83.      * @param time 
  84.      *            the entry modification time in number of milliseconds since 
  85.      *            the epoch 
  86.      * @see #getTime() 
  87.      */  
  88.     public void setTime(long time) {  
  89.         this.time = javaToDosTime(time);  
  90.     }  
  91.   
  92.     /** 
  93.      * Returns the modification time of the entry, or -1 if not specified. 
  94.      *  
  95.      * @return the modification time of the entry, or -1 if not specified 
  96.      * @see #setTime(long) 
  97.      */  
  98.     public long getTime() {  
  99.         return time != -1 ? dosToJavaTime(time) : -1;  
  100.     }  
  101.   
  102.     /** 
  103.      * Sets the uncompressed size of the entry data. 
  104.      *  
  105.      * @param size 
  106.      *            the uncompressed size in bytes 
  107.      * @exception IllegalArgumentException 
  108.      *                if the specified size is less than 0 or greater than 
  109.      *                0xFFFFFFFF bytes 
  110.      * @see #getSize() 
  111.      */  
  112.     public void setSize(long size) {  
  113.         if (size < 0 || size > 0xFFFFFFFFL) {  
  114.             throw new IllegalArgumentException("invalid entry size");  
  115.         }  
  116.         this.size = size;  
  117.     }  
  118.   
  119.     /** 
  120.      * Returns the uncompressed size of the entry data, or -1 if not known. 
  121.      *  
  122.      * @return the uncompressed size of the entry data, or -1 if not known 
  123.      * @see #setSize(long) 
  124.      */  
  125.     public long getSize() {  
  126.         return size;  
  127.     }  
  128.   
  129.     /** 
  130.      * Returns the size of the compressed entry data, or -1 if not known. In the 
  131.      * case of a stored entry, the compressed size will be the same as the 
  132.      * uncompressed size of the entry. 
  133.      *  
  134.      * @return the size of the compressed entry data, or -1 if not known 
  135.      * @see #setCompressedSize(long) 
  136.      */  
  137.     public long getCompressedSize() {  
  138.         return csize;  
  139.     }  
  140.   
  141.     /** 
  142.      * Sets the size of the compressed entry data. 
  143.      *  
  144.      * @param csize 
  145.      *            the compressed size to set to 
  146.      * @see #getCompressedSize() 
  147.      */  
  148.     public void setCompressedSize(long csize) {  
  149.         this.csize = csize;  
  150.     }  
  151.   
  152.     /** 
  153.      * Sets the CRC-32 checksum of the uncompressed entry data. 
  154.      *  
  155.      * @param crc 
  156.      *            the CRC-32 value 
  157.      * @exception IllegalArgumentException 
  158.      *                if the specified CRC-32 value is less than 0 or greater 
  159.      *                than 0xFFFFFFFF 
  160.      * @see #setCrc(long) 
  161.      */  
  162.     public void setCrc(long crc) {  
  163.         if (crc < 0 || crc > 0xFFFFFFFFL) {  
  164.             throw new IllegalArgumentException("invalid entry crc-32");  
  165.         }  
  166.         this.crc = crc;  
  167.     }  
  168.   
  169.     /** 
  170.      * Returns the CRC-32 checksum of the uncompressed entry data, or -1 if not 
  171.      * known. 
  172.      *  
  173.      * @return the CRC-32 checksum of the uncompressed entry data, or -1 if not 
  174.      *         known 
  175.      * @see #getCrc() 
  176.      */  
  177.     public long getCrc() {  
  178.         return crc;  
  179.     }  
  180.   
  181.     /** 
  182.      * Sets the compression method for the entry. 
  183.      *  
  184.      * @param method 
  185.      *            the compression method, either STORED or DEFLATED 
  186.      * @exception IllegalArgumentException 
  187.      *                if the specified compression method is invalid 
  188.      * @see #getMethod() 
  189.      */  
  190.     public void setMethod(int method) {  
  191.         if (method != STORED && method != DEFLATED) {  
  192.             throw new IllegalArgumentException("invalid compression method");  
  193.         }  
  194.         this.method = method;  
  195.     }  
  196.   
  197.     /** 
  198.      * Returns the compression method of the entry, or -1 if not specified. 
  199.      *  
  200.      * @return the compression method of the entry, or -1 if not specified 
  201.      * @see #setMethod(int) 
  202.      */  
  203.     public int getMethod() {  
  204.         return method;  
  205.     }  
  206.   
  207.     /** 
  208.      * Sets the optional extra field data for the entry. 
  209.      *  
  210.      * @param extra 
  211.      *            the extra field data bytes 
  212.      * @exception IllegalArgumentException 
  213.      *                if the length of the specified extra field data is greater 
  214.      *                than 0xFFFF bytes 
  215.      * @see #getExtra() 
  216.      */  
  217.     public void setExtra(byte[] extra) {  
  218.         if (extra != null && extra.length > 0xFFFF) {  
  219.             throw new IllegalArgumentException("invalid extra field length");  
  220.         }  
  221.         this.extra = extra;  
  222.     }  
  223.   
  224.     /** 
  225.      * Returns the extra field data for the entry, or null if none. 
  226.      *  
  227.      * @return the extra field data for the entry, or null if none 
  228.      * @see #setExtra(byte[]) 
  229.      */  
  230.     public byte[] getExtra() {  
  231.         return extra;  
  232.     }  
  233.   
  234.     /** 
  235.      * Sets the optional comment string for the entry. 
  236.      *  
  237.      * @param comment 
  238.      *            the comment string 
  239.      * @exception IllegalArgumentException 
  240.      *                if the length of the specified comment string is greater 
  241.      *                than 0xFFFF bytes 
  242.      * @see #getComment() 
  243.      */  
  244.     public void setComment(String comment) {  
  245.         if (comment != null && comment.length() > 0xffff / 3  
  246.                 && ZipOutputStream.getUTF8Length(comment) > 0xffff) {  
  247.             throw new IllegalArgumentException("invalid entry comment length");  
  248.         }  
  249.         this.comment = comment;  
  250.     }  
  251.   
  252.     /** 
  253.      * Returns the comment string for the entry, or null if none. 
  254.      *  
  255.      * @return the comment string for the entry, or null if none 
  256.      * @see #setComment(String) 
  257.      */  
  258.     public String getComment() {  
  259.         return comment;  
  260.     }  
  261.   
  262.     /** 
  263.      * Returns true if this is a directory entry. A directory entry is defined 
  264.      * to be one whose name ends with a '/'. 
  265.      *  
  266.      * @return true if this is a directory entry 
  267.      */  
  268.     public boolean isDirectory() {  
  269.         return name.endsWith("/");  
  270.     }  
  271.   
  272.     /** 
  273.      * Returns a string representation of the ZIP entry. 
  274.      */  
  275.     public String toString() {  
  276.         return getName();  
  277.     }  
  278.   
  279.     /* 
  280.      * Converts DOS time to Java time (number of milliseconds since epoch). 
  281.      */  
  282.     private static long dosToJavaTime(long dtime) {  
  283.         Date d = new Date((int) (((dtime >> 25) & 0x7f) + 80),  
  284.                 (int) (((dtime >> 21) & 0x0f) - 1),  
  285.                 (int) ((dtime >> 16) & 0x1f), (int) ((dtime >> 11) & 0x1f),  
  286.                 (int) ((dtime >> 5) & 0x3f), (int) ((dtime << 1) & 0x3e));  
  287.         return d.getTime();  
  288.     }  
  289.   
  290.     /* 
  291.      * Converts Java time to DOS time. 
  292.      */  
  293.     private static long javaToDosTime(long time) {  
  294.         Date d = new Date(time);  
  295.         int year = d.getYear() + 1900;  
  296.         if (year < 1980) {  
  297.             return (1 << 21) | (1 << 16);  
  298.         }  
  299.         return (year - 1980) << 25 | (d.getMonth() + 1) << 21  
  300.                 | d.getDate() << 16 | d.getHours() << 11 | d.getMinutes() << 5  
  301.                 | d.getSeconds() >> 1;  
  302.     }  
  303.   
  304.     /** 
  305.      * Returns the hash code value for this entry. 
  306.      */  
  307.     public int hashCode() {  
  308.         return name.hashCode();  
  309.     }  
  310.   
  311.     /** 
  312.      * Returns a copy of this entry. 
  313.      */  
  314.     public Object clone() {  
  315.         try {  
  316.             ZipEntry e = (ZipEntry) super.clone();  
  317.             e.extra = (extra == null ? null : (byte[]) extra.clone());  
  318.             return e;  
  319.         } catch (CloneNotSupportedException e) {  
  320.             // This should never happen, since we are Cloneable  
  321.             throw new InternalError();  
  322.         }  
  323.     }  
  324. }  


有了上面那两个类后,我们就不用java.util.zip包下的这两个类来做压缩,而是用来面的修改后的类来做,我写了一个简单的测试程序如下:
Java代码  收藏代码
  1. package test;  
  2.   
  3. import java.io.File;  
  4. import java.io.FileInputStream;  
  5. import java.io.FileNotFoundException;  
  6. import java.io.FileOutputStream;  
  7. import java.io.IOException;  
  8.   
  9. import my.java.util.zip.ZipEntry;  
  10. import my.java.util.zip.ZipOutputStream;  
  11.   
  12. public class zip {  
  13.     private ZipOutputStream zipOutputStream;  
  14.     private FileOutputStream fos = null;  
  15.       
  16.     public zip(File in , File out)  
  17.     {  
  18.         try {  
  19.             fos = new FileOutputStream(out);  
  20.         } catch (FileNotFoundException e) {  
  21.             e.printStackTrace();  
  22.         }  
  23.         zipOutputStream = new ZipOutputStream(fos,"GBK");//只能是GBK,用UTF-8不行  
  24.           
  25.         doZip(in, zipOutputStream, null);  
  26.           
  27.         closeZipOutputStream();  
  28.     }  
  29.       
  30.     /** 
  31.      * 用递归调用的方式将一个文件夹下的所有文件压缩进压缩包里 
  32.      * @param  input 输入要压缩的文件的路径 
  33.      * @param zos 压缩输出流 
  34.      * @param relativePath 文件或文件夹在压缩包里的相对路径,一开始应将相对路径设置为null 
  35.      */  
  36.     public void doZip(File input , ZipOutputStream zos , String relativePath)  
  37.     {  
  38.         FileInputStream fis;  
  39.         byte[] b = new byte[1024];  
  40.           
  41.         try {  
  42.               
  43.             if(input.isDirectory())  
  44.             {  
  45.                 relativePath = relativePath == null ? input.getName() : relativePath  + "/" + input.getName();  
  46.               
  47.                 zos.putNextEntry(new ZipEntry(relativePath + "/"));//ZipEntry应该是用来设置压缩文件所存放的相对路径的,当是文件夹时一定要后面加上"/",是文件则不用加  
  48.                   
  49.                 File[] fileList = input.listFiles();  
  50.                 for(int i = 0 ; i < fileList.length ; i++)  
  51.                 {  
  52.                     if(fileList[i].isDirectory())  
  53.                     {  
  54.                         doZip(fileList[i] , zos , relativePath);  
  55.                     }  
  56.                     else   
  57.                     {     
  58.                         zos.putNextEntry(new ZipEntry(relativePath + "/" +  fileList[i].getName()));//这个一定不要忘记了,不然文件是压缩不进入的哦  
  59.                         fis = new FileInputStream(fileList[i]);  
  60.                         while(fis.read(b) != -1)  
  61.                         {  
  62.                             zos.write(b);  
  63.                         }  
  64.                         fis.close();  
  65.                     }  
  66.                 }  
  67.             }  
  68.             else {  
  69.                   
  70.                 relativePath = relativePath == null ? input.getName() : relativePath + "/" +  input.getName();  
  71.               
  72.                 zos.putNextEntry(new ZipEntry(relativePath));//文件不用加上"/"  
  73.                   
  74.                 fis = new FileInputStream(input);  
  75.                 while(fis.read(b) != -1)  
  76.                 {  
  77.                     zos.write(b);  
  78.                 }  
  79.                 fis.close();  
  80.             }  
  81.   
  82.         } catch (FileNotFoundException e) {  
  83.             e.printStackTrace();  
  84.         }catch (IOException e) {  
  85.             e.printStackTrace();  
  86.         }  
  87.     }  
  88.       
  89.     //关闭输出流  
  90.     public void closeZipOutputStream()  
  91.     {  
  92.         try {  
  93.             zipOutputStream.close();  
  94.         } catch (IOException e) {  
  95.             e.printStackTrace();  
  96.         }  
  97.     }  
  98.       
  99.     //简单测试  
  100.     public static void main(String[] args)  
  101.     {  
  102.         zip test = new zip(new File("F:\\MQ") , new File("F:/MQ.zip"));  
  103.           
  104.         System.out.println("压缩完成");  
  105.     }  
  106.   
  107. }  


解压程序我也写了,如下:

Java代码  收藏代码
  1. package test;  
  2.   
  3. import java.io.File;  
  4. import java.io.FileInputStream;  
  5. import java.io.FileNotFoundException;  
  6. import java.io.FileOutputStream;  
  7. import java.io.IOException;  
  8. import java.util.zip.ZipException;  
  9. import java.util.zip.ZipFile;  
  10.   
  11. import my.java.util.zip.ZipEntry;  
  12. import my.java.util.zip.ZipInputStream;  
  13.   
  14. //解压简单例子  
  15. public class unZip {  
  16.   
  17.     File in;  
  18.     File out;  
  19.     private ZipInputStream zis;  
  20.       
  21.     public unZip(File in , File out)  
  22.     {  
  23.         this.in = in;  
  24.         this.out = out;  
  25.         initial();  
  26.     }  
  27.       
  28.     public void initial()  
  29.     {  
  30.         //下面是用来检查输入的文件是否是zip文件类型用的,若输入的是.rar类型也会报异常  
  31.         try {  
  32.             ZipFile zipFile = new ZipFile(in);  
  33.             zipFile.close();  
  34.         } catch (ZipException e1) {  
  35.             e1.printStackTrace();  
  36.             return ;  
  37.         } catch (IOException e1) {  
  38.             e1.printStackTrace();  
  39.             return ;  
  40.         }  
  41.           
  42.         if(out == null || !out.isDirectory())  
  43.         {  
  44.             System.out.println("请选择正确的解压存放的目录!");  
  45.             return ;  
  46.         }  
  47.           
  48.         try {  
  49.             zis = new ZipInputStream(new FileInputStream(in),"GBK");//支持中文的地方  
  50.             doUnZip();  
  51.         } catch (FileNotFoundException e) {  
  52.             e.printStackTrace();  
  53.             return ;  
  54.         }  
  55.     }  
  56.       
  57.     public void doUnZip()  
  58.     {  
  59.         String pathName;  
  60.         ZipEntry zipEntry;  
  61.         File output;  
  62.         FileOutputStream fos;  
  63.         byte[] b;  
  64.         int len;  
  65.         String desPath;//存放的目标路径  
  66.         String tempPath;  
  67.           
  68.         desPath = out.getAbsolutePath();  
  69.           
  70.         try {  
  71.             zipEntry = zis.getNextEntry();//用它可以遍历在压缩包里的所有条目(包括文件和文件夹都会识别出来)  
  72.             while(zipEntry != null)  
  73.             {  
  74.                 System.out.println(zipEntry.getName());  
  75.                   
  76.                 tempPath = zipEntry.getName();  
  77.                   
  78.                 //这里的文件路径用"\\"和"/"混合也是可以正确的创建目录或访问目录等,还是比较方便的  
  79.                 if(desPath.endsWith("\\") || desPath.endsWith("/"))  
  80.                     tempPath = desPath + tempPath;  
  81.                 else   
  82.                     tempPath = desPath + File.separator + tempPath;  
  83.               
  84.                 output = new File(tempPath);  
  85.                   
  86.                 if(zipEntry.isDirectory())//这里注意啦,不是output.isDirectory()来判断,是用ZipEntry来判断  
  87.                 {  
  88.                     /* 
  89.                      * File类的mkdir()和mkdirs()区别 
  90.                      * 简单来说,mkdir()就是创建一个目录,但前提是要创建的目录的父目录一定要存在。 例如:要创建D:\myeclipseprg7\CompilerTest\WebRoot\works 这个目录,那么D:\myeclipseprg7\CompilerTest\WebRoot\这个目录就一定要存在,否则用mkdir()无法成功创建目录。如果父目录不存在,我们可以用mkdirs(),这样不管父目录是否存在,都能创建成功。这样看来,似乎mkdir()这个函数没多大用处,今后建议大家只使用mkdirs()。 
  91.                      */  
  92.                     output.mkdirs();  
  93.                 }  
  94.                 else//对于文件就直接输出   
  95.                 {  
  96.                     fos = new FileOutputStream(output);  
  97.                     b = new byte[1024];  
  98.                       
  99.                     while( (len = zis.read(b)) != -1)  
  100.                     {  
  101.                         fos.write(b, 0, len);  
  102.                     }  
  103.                     fos.close();  
  104.                 }  
  105.                   
  106.                 zipEntry = zis.getNextEntry();//下一条条目  
  107.             }  
  108.               
  109.         } catch (IOException e) {  
  110.             e.printStackTrace();  
  111.             return;  
  112.         }  
  113.           
  114.         closeZipInputStream();  
  115.     }  
  116.       
  117.     public void closeZipInputStream()  
  118.     {  
  119.         try {  
  120.             zis.close();  
  121.         } catch (IOException e) {  
  122.             e.printStackTrace();  
  123.             return ;  
  124.         }  
  125.     }  
  126.       
  127.     public static void main(String[] args)  
  128.     {  
  129.         unZip test = new unZip(new File("F:\\chenwenbiao.zip"), new File("F:\\"));  
  130.     }  
  131.       
  132. }  


我以为用修改后的my.java.util.zip.ZipOutputStream或my.java.util.zip.ZipInputStream就可以解决问题,我将这两个类拷给同学,在他那里会出错,原来这两个类修改也包括了对它们引用到的类的修改,我现将它们打包发上来,导入就可以用了,中文名的压缩和解压缩的问题也可以解决了。
0 0