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

所以要实现解压缩,就得对DeflaterOutputStream.java、InflaterInputStream.java、ZipConstants.java、ZipEntry.java、ZipInputStream.java以及ZipOutputStream.java这些相关的类进行修改,过程如下:

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

DeflaterOutputStream.java:

  1. package cn.edu.xdian.crytoll;
  2.  
  3. import java.io.FilterOutputStream;
  4. import java.io.IOException;
  5. import java.io.OutputStream;
  6. import java.util.zip.Deflater;
  7.  
  8. /**
  9. * This class implements an output stream filter for compressing data in
  10. * the "deflate" compression format. It is also used as the basis for other
  11. * types of compression filters, such as GZIPOutputStream.
  12. *
  13. * @see Deflater
  14. * @version 1.36, 03/13/06
  15. * @author David Connelly
  16. */
  17. public
  18. class DeflaterOutputStream extends FilterOutputStream {
  19. /**
  20. * Compressor for this stream.
  21. */
  22. protected Deflater def;
  23.  
  24. /**
  25. * Output buffer for writing compressed data.
  26. */
  27. protected byte[] buf;
  28.  
  29. /**
  30. * Indicates that the stream has been closed.
  31. */
  32.  
  33. private boolean closed = false;
  34.  
  35. /**
  36. * Creates a new output stream with the specified compressor and
  37. * buffer size.
  38. * @param out the output stream
  39. * @param def the compressor ("deflater")
  40. * @param size the output buffer size
  41. * @exception IllegalArgumentException if size is <= 0
  42. */
  43. public DeflaterOutputStream(OutputStream out, Deflater def, int size) {
  44. super(out);
  45. if (out == null || def == null) {
  46. throw new NullPointerException();
  47. } else if (size <= 0) {
  48. throw new IllegalArgumentException("buffer size <= 0");
  49. }
  50. this.def = def;
  51. buf = new byte[size];
  52. }
  53.  
  54. /**
  55. * Creates a new output stream with the specified compressor and
  56. * a default buffer size.
  57. * @param out the output stream
  58. * @param def the compressor ("deflater")
  59. */
  60. public DeflaterOutputStream(OutputStream out, Deflater def) {
  61. this(out, def, 512);
  62. }
  63.  
  64. boolean usesDefaultDeflater = false;
  65.  
  66. /**
  67. * Creates a new output stream with a default compressor and buffer size.
  68. * @param out the output stream
  69. */
  70. public DeflaterOutputStream(OutputStream out) {
  71. this(out, new Deflater());
  72. usesDefaultDeflater = true;
  73. }
  74.  
  75. /**
  76. * Writes a byte to the compressed output stream. This method will
  77. * block until the byte can be written.
  78. * @param b the byte to be written
  79. * @exception IOException if an I/O error has occurred
  80. */
  81. public void write(int b) throws IOException {
  82. byte[] buf = new byte[1];
  83. buf[0] = (byte)(b & 0xff);
  84. write(buf, 0, 1);
  85. }
  86.  
  87. /**
  88. * Writes an array of bytes to the compressed output stream. This
  89. * method will block until all the bytes are written.
  90. * @param b the data to be written
  91. * @param off the start offset of the data
  92. * @param len the length of the data
  93. * @exception IOException if an I/O error has occurred
  94. */
  95. public void write(byte[] b, int off, int len) throws IOException {
  96. if (def.finished()) {
  97. throw new IOException("write beyond end of stream");
  98. }
  99. if ((off | len | (off + len) | (b.length - (off + len))) < 0) {
  100. throw new IndexOutOfBoundsException();
  101. } else if (len == 0) {
  102. return;
  103. }
  104. if (!def.finished()) {
  105. // Deflate no more than stride bytes at a time. This avoids
  106. // excess copying in deflateBytes (see Deflater.c)
  107. int stride = buf.length;
  108. for (int i = 0; i < len; i+= stride) {
  109. def.setInput(b, off + i, Math.min(stride, len - i));
  110. while (!def.needsInput()) {
  111. deflate();
  112. }
  113. }
  114. }
  115. }
  116.  
  117. /**
  118. * Finishes writing compressed data to the output stream without closing
  119. * the underlying stream. Use this method when applying multiple filters
  120. * in succession to the same output stream.
  121. * @exception IOException if an I/O error has occurred
  122. */
  123. public void finish() throws IOException {
  124. if (!def.finished()) {
  125. def.finish();
  126. while (!def.finished()) {
  127. deflate();
  128. }
  129. }
  130. }
  131.  
  132. /**
  133. * Writes remaining compressed data to the output stream and closes the
  134. * underlying stream.
  135. * @exception IOException if an I/O error has occurred
  136. */
  137. public void close() throws IOException {
  138. if (!closed) {
  139. finish();
  140. if (usesDefaultDeflater)
  141. def.end();
  142. out.close();
  143. closed = true;
  144. }
  145. }
  146.  
  147. /**
  148. * Writes next block of compressed data to the output stream.
  149. * @throws IOException if an I/O error has occurred
  150. */
  151. protected void deflate() throws IOException {
  152. int len = def.deflate(buf, 0, buf.length);
  153. if (len > 0) {
  154. out.write(buf, 0, len);
  155. }
  156. }
  157. }

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

InflaterInputStream.java:

  1. package cn.edu.xdian.crytoll;
  2.  
  3. import java.io.EOFException;
  4. import java.io.FilterInputStream;
  5. import java.io.IOException;
  6. import java.io.InputStream;
  7. import java.util.zip.DataFormatException;
  8. import java.util.zip.Inflater;
  9. import java.util.zip.ZipException;
  10.  
  11. /**
  12. * This class implements a stream filter for uncompressing data in the
  13. * "deflate" compression format. It is also used as the basis for other
  14. * decompression filters, such as GZIPInputStream.
  15. *
  16. * @see Inflater
  17. * @version 1.40, 04/07/06
  18. * @author David Connelly
  19. */
  20. public
  21. class InflaterInputStream extends FilterInputStream {
  22. /**
  23. * Decompressor for this stream.
  24. */
  25. protected Inflater inf;
  26.  
  27. /**
  28. * Input buffer for decompression.
  29. */
  30. protected byte[] buf;
  31.  
  32. /**
  33. * Length of input buffer.
  34. */
  35. protected int len;
  36.  
  37. private boolean closed = false;
  38. // this flag is set to true after EOF has reached
  39. private boolean reachEOF = false;
  40.  
  41. /**
  42. * Check to make sure that this stream has not been closed
  43. */
  44. private void ensureOpen() throws IOException {
  45. if (closed) {
  46. throw new IOException("Stream closed");
  47. }
  48. }
  49.  
  50. /**
  51. * Creates a new input stream with the specified decompressor and
  52. * buffer size.
  53. * @param in the input stream
  54. * @param inf the decompressor ("inflater")
  55. * @param size the input buffer size
  56. * @exception IllegalArgumentException if size is <= 0
  57. */
  58. public InflaterInputStream(InputStream in, Inflater inf, int size) {
  59. super(in);
  60. if (in == null || inf == null) {
  61. throw new NullPointerException();
  62. } else if (size <= 0) {
  63. throw new IllegalArgumentException("buffer size <= 0");
  64. }
  65. this.inf = inf;
  66. buf = new byte[size];
  67. }
  68.  
  69. /**
  70. * Creates a new input stream with the specified decompressor and a
  71. * default buffer size.
  72. * @param in the input stream
  73. * @param inf the decompressor ("inflater")
  74. */
  75. public InflaterInputStream(InputStream in, Inflater inf) {
  76. this(in, inf, 512);
  77. }
  78.  
  79. boolean usesDefaultInflater = false;
  80.  
  81. /**
  82. * Creates a new input stream with a default decompressor and buffer size.
  83. * @param in the input stream
  84. */
  85. public InflaterInputStream(InputStream in) {
  86. this(in, new Inflater());
  87. usesDefaultInflater = true;
  88. }
  89.  
  90. private byte[] singleByteBuf = new byte[1];
  91.  
  92. /**
  93. * Reads a byte of uncompressed data. This method will block until
  94. * enough input is available for decompression.
  95. * @return the byte read, or -1 if end of compressed input is reached
  96. * @exception IOException if an I/O error has occurred
  97. */
  98. public int read() throws IOException {
  99. ensureOpen();
  100. return read(singleByteBuf, 0, 1) == -1 ? -1 : singleByteBuf[0] & 0xff;
  101. }
  102.  
  103. /**
  104. * Reads uncompressed data into an array of bytes. If <code>len</code> is not
  105. * zero, the method will block until some input can be decompressed; otherwise,
  106. * no bytes are read and <code>0</code> is returned.
  107. * @param b the buffer into which the data is read
  108. * @param off the start offset in the destination array <code>b</code>
  109. * @param len the maximum number of bytes read
  110. * @return the actual number of bytes read, or -1 if the end of the
  111. * compressed input is reached or a preset dictionary is needed
  112. * @exception NullPointerException If <code>b</code> is <code>null</code>.
  113. * @exception IndexOutOfBoundsException If <code>off</code> is negative,
  114. * <code>len</code> is negative, or <code>len</code> is greater than
  115. * <code>b.length - off</code>
  116. * @exception ZipException if a ZIP format error has occurred
  117. * @exception IOException if an I/O error has occurred
  118. */
  119. public int read(byte[] b, int off, int len) throws IOException {
  120. ensureOpen();
  121. if (b == null) {
  122. throw new NullPointerException();
  123. } else if (off < 0 || len < 0 || len > b.length - off) {
  124. throw new IndexOutOfBoundsException();
  125. } else if (len == 0) {
  126. return 0;
  127. }
  128. try {
  129. int n;
  130. while ((n = inf.inflate(b, off, len)) == 0) {
  131. if (inf.finished() || inf.needsDictionary()) {
  132. reachEOF = true;
  133. return -1;
  134. }
  135. if (inf.needsInput()) {
  136. fill();
  137. }
  138. }
  139. return n;
  140. } catch (DataFormatException e) {
  141. String s = e.getMessage();
  142. throw new ZipException(s != null ? s : "Invalid ZLIB data format");
  143. }
  144. }
  145.  
  146. /**
  147. * Returns 0 after EOF has been reached, otherwise always return 1.
  148. * <p>
  149. * Programs should not count on this method to return the actual number
  150. * of bytes that could be read without blocking.
  151. *
  152. * @return 1 before EOF and 0 after EOF.
  153. * @exception IOException if an I/O error occurs.
  154. *
  155. */
  156. public int available() throws IOException {
  157. ensureOpen();
  158. if (reachEOF) {
  159. return 0;
  160. } else {
  161. return 1;
  162. }
  163. }
  164.  
  165. private byte[] b = new byte[512];
  166.  
  167. /**
  168. * Skips specified number of bytes of uncompressed data.
  169. * @param n the number of bytes to skip
  170. * @return the actual number of bytes skipped.
  171. * @exception IOException if an I/O error has occurred
  172. * @exception IllegalArgumentException if n < 0
  173. */
  174. public long skip(long n) throws IOException {
  175. if (n < 0) {
  176. throw new IllegalArgumentException("negative skip length");
  177. }
  178. ensureOpen();
  179. int max = (int)Math.min(n, Integer.MAX_VALUE);
  180. int total = 0;
  181. while (total < max) {
  182. int len = max - total;
  183. if (len > b.length) {
  184. len = b.length;
  185. }
  186. len = read(b, 0, len);
  187. if (len == -1) {
  188. reachEOF = true;
  189. break;
  190. }
  191. total += len;
  192. }
  193. return total;
  194. }
  195.  
  196. /**
  197. * Closes this input stream and releases any system resources associated
  198. * with the stream.
  199. * @exception IOException if an I/O error has occurred
  200. */
  201. public void close() throws IOException {
  202. if (!closed) {
  203. if (usesDefaultInflater)
  204. inf.end();
  205. in.close();
  206. closed = true;
  207. }
  208. }
  209.  
  210. /**
  211. * Fills input buffer with more data to decompress.
  212. * @exception IOException if an I/O error has occurred
  213. */
  214. protected void fill() throws IOException {
  215. ensureOpen();
  216. len = in.read(buf, 0, buf.length);
  217. if (len == -1) {
  218. throw new EOFException("Unexpected end of ZLIB input stream");
  219. }
  220. inf.setInput(buf, 0, len);
  221. }
  222.  
  223. /**
  224. * Tests if this input stream supports the <code>mark</code> and
  225. * <code>reset</code> methods. The <code>markSupported</code>
  226. * method of <code>InflaterInputStream</code> returns
  227. * <code>false</code>.
  228. *
  229. * @return a <code>boolean</code> indicating if this stream type supports
  230. * the <code>mark</code> and <code>reset</code> methods.
  231. * @see java.io.InputStream#mark(int)
  232. * @see java.io.InputStream#reset()
  233. */
  234. public boolean markSupported() {
  235. return false;
  236. }
  237.  
  238. /**
  239. * Marks the current position in this input stream.
  240. *
  241. * <p> The <code>mark</code> method of <code>InflaterInputStream</code>
  242. * does nothing.
  243. *
  244. * @param readlimit the maximum limit of bytes that can be read before
  245. * the mark position becomes invalid.
  246. * @see java.io.InputStream#reset()
  247. */
  248. public synchronized void mark(int readlimit) {
  249. }
  250.  
  251. /**
  252. * Repositions this stream to the position at the time the
  253. * <code>mark</code> method was last called on this input stream.
  254. *
  255. * <p> The method <code>reset</code> for class
  256. * <code>InflaterInputStream</code> does nothing except throw an
  257. * <code>IOException</code>.
  258. *
  259. * @exception IOException if this method is invoked.
  260. * @see java.io.InputStream#mark(int)
  261. * @see java.io.IOException
  262. */
  263. public synchronized void reset() throws IOException {
  264. throw new IOException("mark/reset not supported");
  265. }
  266. }

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

ZipConstants.java:

  1. package cn.edu.xdian.crytoll;
  2. interface ZipConstants {
  3. /*
  4. * Header signatures
  5. */
  6. static long LOCSIG = 0x04034b50L; // "PK\003\004"
  7. static long EXTSIG = 0x08074b50L; // "PK\007\008"
  8. static long CENSIG = 0x02014b50L; // "PK\001\002"
  9. static long ENDSIG = 0x06054b50L; // "PK\005\006"
  10.  
  11. /*
  12. * Header sizes in bytes (including signatures)
  13. */
  14. static final int LOCHDR = 30; // LOC header size
  15. static final int EXTHDR = 16; // EXT header size
  16. static final int CENHDR = 46; // CEN header size
  17. static final int ENDHDR = 22; // END header size
  18.  
  19. /*
  20. * Local file (LOC) header field offsets
  21. */
  22. static final int LOCVER = 4; // version needed to extract
  23. static final int LOCFLG = 6; // general purpose bit flag
  24. static final int LOCHOW = 8; // compression method
  25. static final int LOCTIM = 10; // modification time
  26. static final int LOCCRC = 14; // uncompressed file crc-32 value
  27. static final int LOCSIZ = 18; // compressed size
  28. static final int LOCLEN = 22; // uncompressed size
  29. static final int LOCNAM = 26; // filename length
  30. static final int LOCEXT = 28; // extra field length
  31.  
  32. /*
  33. * Extra local (EXT) header field offsets
  34. */
  35. static final int EXTCRC = 4; // uncompressed file crc-32 value
  36. static final int EXTSIZ = 8; // compressed size
  37. static final int EXTLEN = 12; // uncompressed size
  38.  
  39. /*
  40. * Central directory (CEN) header field offsets
  41. */
  42. static final int CENVEM = 4; // version made by
  43. static final int CENVER = 6; // version needed to extract
  44. static final int CENFLG = 8; // encrypt, decrypt flags
  45. static final int CENHOW = 10; // compression method
  46. static final int CENTIM = 12; // modification time
  47. static final int CENCRC = 16; // uncompressed file crc-32 value
  48. static final int CENSIZ = 20; // compressed size
  49. static final int CENLEN = 24; // uncompressed size
  50. static final int CENNAM = 28; // filename length
  51. static final int CENEXT = 30; // extra field length
  52. static final int CENCOM = 32; // comment length
  53. static final int CENDSK = 34; // disk number start
  54. static final int CENATT = 36; // internal file attributes
  55. static final int CENATX = 38; // external file attributes
  56. static final int CENOFF = 42; // LOC header offset
  57.  
  58. /*
  59. * End of central directory (END) header field offsets
  60. */
  61. static final int ENDSUB = 8; // number of entries on this disk
  62. static final int ENDTOT = 10; // total number of entries
  63. static final int ENDSIZ = 12; // central directory size in bytes
  64. static final int ENDOFF = 16; // offset of first CEN header
  65. static final int ENDCOM = 20; // zip file comment length
  66. }
  1. 在包中新建ZipEntry类,代码如下:

ZipEntry.java:

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

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

ZipInputStream.java:

  1. package cn.edu.xdian.crytoll;
  2. import java.io.EOFException;
  3. import java.io.IOException;
  4. import java.io.InputStream;
  5. import java.io.PushbackInputStream;
  6. import java.io.UnsupportedEncodingException;
  7. import java.util.zip.CRC32;
  8. import java.util.zip.Inflater;
  9. import java.util.zip.ZipException;
  10.  
  11. /**
  12. * This class implements an input stream filter for reading files in the
  13. * ZIP file format. Includes support for both compressed and uncompressed
  14. * entries.
  15. *
  16. * @author David Connelly
  17. * @version 1.44, 06/15/07
  18. */
  19. public
  20. class ZipInputStream extends InflaterInputStream implements ZipConstants {
  21. private ZipEntry entry;
  22. private int flag;
  23. private CRC32 crc = new CRC32();
  24. private long remaining;
  25. private byte[] tmpbuf = new byte[512];
  26.  
  27. private static final int STORED = ZipEntry.STORED;
  28. private static final int DEFLATED = ZipEntry.DEFLATED;
  29.  
  30. private boolean closed = false;
  31. // this flag is set to true after EOF has reached for
  32. // one entry
  33. private boolean entryEOF = false;
  34.  
  35. /**
  36. * Check to make sure that this stream has not been closed
  37. */
  38. private void ensureOpen() throws IOException {
  39. if (closed) {
  40. throw new IOException("Stream closed");
  41. }
  42. }
  43.  
  44. /**
  45. * Creates a new ZIP input stream.
  46. * @param in the actual input stream
  47. */
  48. public ZipInputStream(InputStream in) {
  49. super(new PushbackInputStream(in, 512), new Inflater(true), 512);
  50. usesDefaultInflater = true;
  51. if(in == null) {
  52. throw new NullPointerException("in is null");
  53. }
  54. }
  55.  
  56. /**
  57. * Reads the next ZIP file entry and positions the stream at the
  58. * beginning of the entry data.
  59. * @return the next ZIP file entry, or null if there are no more entries
  60. * @exception ZipException if a ZIP file error has occurred
  61. * @exception IOException if an I/O error has occurred
  62. */
  63. public ZipEntry getNextEntry() throws IOException {
  64. ensureOpen();
  65. if (entry != null) {
  66. closeEntry();
  67. }
  68. crc.reset();
  69. inf.reset();
  70. if ((entry = readLOC()) == null) {
  71. return null;
  72. }
  73. if (entry.method == STORED) {
  74. remaining = entry.size;
  75. }
  76. entryEOF = false;
  77. return entry;
  78. }
  79.  
  80. /**
  81. * Closes the current ZIP entry and positions the stream for reading the
  82. * next entry.
  83. * @exception ZipException if a ZIP file error has occurred
  84. * @exception IOException if an I/O error has occurred
  85. */
  86. public void closeEntry() throws IOException {
  87. ensureOpen();
  88. while (read(tmpbuf, 0, tmpbuf.length) != -1) ;
  89. entryEOF = true;
  90. }
  91.  
  92. /**
  93. * Returns 0 after EOF has reached for the current entry data,
  94. * otherwise always return 1.
  95. * <p>
  96. * Programs should not count on this method to return the actual number
  97. * of bytes that could be read without blocking.
  98. *
  99. * @return 1 before EOF and 0 after EOF has reached for current entry.
  100. * @exception IOException if an I/O error occurs.
  101. *
  102. */
  103. public int available() throws IOException {
  104. ensureOpen();
  105. if (entryEOF) {
  106. return 0;
  107. } else {
  108. return 1;
  109. }
  110. }
  111.  
  112. /**
  113. * Reads from the current ZIP entry into an array of bytes.
  114. * If <code>len</code> is not zero, the method
  115. * blocks until some input is available; otherwise, no
  116. * bytes are read and <code>0</code> is returned.
  117. * @param b the buffer into which the data is read
  118. * @param off the start offset in the destination array <code>b</code>
  119. * @param len the maximum number of bytes read
  120. * @return the actual number of bytes read, or -1 if the end of the
  121. * entry is reached
  122. * @exception NullPointerException If <code>b</code> is <code>null</code>.
  123. * @exception IndexOutOfBoundsException If <code>off</code> is negative,
  124. * <code>len</code> is negative, or <code>len</code> is greater than
  125. * <code>b.length - off</code>
  126. * @exception ZipException if a ZIP file error has occurred
  127. * @exception IOException if an I/O error has occurred
  128. */
  129. public int read(byte[] b, int off, int len) throws IOException {
  130. ensureOpen();
  131. if (off < 0 || len < 0 || off > b.length - len) {
  132. throw new IndexOutOfBoundsException();
  133. } else if (len == 0) {
  134. return 0;
  135. }
  136.  
  137. if (entry == null) {
  138. return -1;
  139. }
  140. switch (entry.method) {
  141. case DEFLATED:
  142. len = super.read(b, off, len);
  143. if (len == -1) {
  144. readEnd(entry);
  145. entryEOF = true;
  146. entry = null;
  147. } else {
  148. crc.update(b, off, len);
  149. }
  150. return len;
  151. case STORED:
  152. if (remaining <= 0) {
  153. entryEOF = true;
  154. entry = null;
  155. return -1;
  156. }
  157. if (len > remaining) {
  158. len = (int)remaining;
  159. }
  160. len = in.read(b, off, len);
  161. if (len == -1) {
  162. throw new ZipException("unexpected EOF");
  163. }
  164. crc.update(b, off, len);
  165. remaining -= len;
  166. if (remaining == 0 && entry.crc != crc.getValue()) {
  167. throw new ZipException(
  168. "invalid entry CRC (expected 0x" + Long.toHexString(entry.crc) +
  169. " but got 0x" + Long.toHexString(crc.getValue()) + ")");
  170. }
  171. return len;
  172. default:
  173. throw new ZipException("invalid compression method");
  174. }
  175. }
  176.  
  177. /**
  178. * Skips specified number of bytes in the current ZIP entry.
  179. * @param n the number of bytes to skip
  180. * @return the actual number of bytes skipped
  181. * @exception ZipException if a ZIP file error has occurred
  182. * @exception IOException if an I/O error has occurred
  183. * @exception IllegalArgumentException if n < 0
  184. */
  185. public long skip(long n) throws IOException {
  186. if (n < 0) {
  187. throw new IllegalArgumentException("negative skip length");
  188. }
  189. ensureOpen();
  190. int max = (int)Math.min(n, Integer.MAX_VALUE);
  191. int total = 0;
  192. while (total < max) {
  193. int len = max - total;
  194. if (len > tmpbuf.length) {
  195. len = tmpbuf.length;
  196. }
  197. len = read(tmpbuf, 0, len);
  198. if (len == -1) {
  199. entryEOF = true;
  200. break;
  201. }
  202. total += len;
  203. }
  204. return total;
  205. }
  206.  
  207. /**
  208. * Closes this input stream and releases any system resources associated
  209. * with the stream.
  210. * @exception IOException if an I/O error has occurred
  211. */
  212. public void close() throws IOException {
  213. if (!closed) {
  214. super.close();
  215. closed = true;
  216. }
  217. }
  218.  
  219. private byte[] b = new byte[256];
  220.  
  221. /*
  222. * Reads local file (LOC) header for next entry.
  223. */
  224. private ZipEntry readLOC() throws IOException {
  225. try {
  226. readFully(tmpbuf, 0, LOCHDR);
  227. } catch (EOFException e) {
  228. return null;
  229. }
  230. if (get32(tmpbuf, 0) != LOCSIG) {
  231. return null;
  232. }
  233. // get the entry name and create the ZipEntry first
  234. int len = get16(tmpbuf, LOCNAM);
  235. int blen = b.length;
  236. if (len > blen) {
  237. do
  238. blen = blen * 2;
  239. while (len > blen);
  240. b = new byte[blen];
  241. }
  242. readFully(b, 0, len);
  243. ZipEntry e = createZipEntry(getUTF8String(b, 0, len));
  244. // now get the remaining fields for the entry
  245. flag = get16(tmpbuf, LOCFLG);
  246. if ((flag & 1) == 1) {
  247. throw new ZipException("encrypted ZIP entry not supported");
  248. }
  249. e.method = get16(tmpbuf, LOCHOW);
  250. e.time = get32(tmpbuf, LOCTIM);
  251. if ((flag & 8) == 8) {
  252. /* "Data Descriptor" present */
  253. if (e.method != DEFLATED) {
  254. throw new ZipException(
  255. "only DEFLATED entries can have EXT descriptor");
  256. }
  257. } else {
  258. e.crc = get32(tmpbuf, LOCCRC);
  259. e.csize = get32(tmpbuf, LOCSIZ);
  260. e.size = get32(tmpbuf, LOCLEN);
  261. }
  262. len = get16(tmpbuf, LOCEXT);
  263. if (len > 0) {
  264. byte[] bb = new byte[len];
  265. readFully(bb, 0, len);
  266. e.setExtra(bb);
  267. }
  268. return e;
  269. }
  270.  
  271. /*
  272. * Fetches a UTF8-encoded String from the specified byte array.
  273. */
  274. private static String getUTF8String(byte[] b, int off, int len)
  275. {
  276.  
  277. try
  278. {
  279. String s = new String(b, off, len, "GBK");
  280. return s;
  281. }
  282. catch (UnsupportedEncodingException e)
  283. {
  284. e.printStackTrace();
  285. }
  286.  
  287. //以上为新添加的解决GBK乱码的
  288.  
  289. // First, count the number of characters in the sequence
  290. int count = 0;
  291. int max = off + len;
  292. int i = off;
  293. while (i < max)
  294. {
  295. int c = b[i++] & 0xff;
  296. switch (c >> 4)
  297. {
  298. case 0:
  299. case 1:
  300. case 2:
  301. case 3:
  302. case 4:
  303. case 5:
  304. case 6:
  305. case 7:
  306. // 0xxxxxxx
  307. count++;
  308. break;
  309. case 12:
  310. case 13:
  311. // 110xxxxx 10xxxxxx
  312. if ((int) (b[i++] & 0xc0) != 0x80)
  313. {
  314. throw new IllegalArgumentException();
  315. }
  316. count++;
  317. break;
  318. case 14:
  319. // 1110xxxx 10xxxxxx 10xxxxxx
  320. if (((int) (b[i++] & 0xc0) != 0x80)
  321. || ((int) (b[i++] & 0xc0) != 0x80))
  322. {
  323. throw new IllegalArgumentException();
  324. }
  325. count++;
  326. break;
  327. default:
  328. // 10xxxxxx, 1111xxxx
  329. throw new IllegalArgumentException();
  330. }
  331. }
  332. if (i != max)
  333. {
  334. throw new IllegalArgumentException();
  335. }
  336. // Now decode the characters...
  337. char[] cs = new char[count];
  338. i = 0;
  339. while (off < max)
  340. {
  341. int c = b[off++] & 0xff;
  342. switch (c >> 4)
  343. {
  344. case 0:
  345. case 1:
  346. case 2:
  347. case 3:
  348. case 4:
  349. case 5:
  350. case 6:
  351. case 7:
  352. // 0xxxxxxx
  353. cs[i++] = (char) c;
  354. break;
  355. case 12:
  356. case 13:
  357. // 110xxxxx 10xxxxxx
  358. cs[i++] = (char) (((c & 0x1f) << 6) | (b[off++] & 0x3f));
  359. break;
  360. case 14:
  361. // 1110xxxx 10xxxxxx 10xxxxxx
  362. int t = (b[off++] & 0x3f) << 6;
  363. cs[i++] = (char) (((c & 0x0f) << 12) | t | (b[off++] & 0x3f));
  364. break;
  365. default:
  366. // 10xxxxxx, 1111xxxx
  367. throw new IllegalArgumentException();
  368. }
  369. }
  370. return new String(cs, 0, count);
  371. }
  372.  
  373. /**
  374. * Creates a new <code>ZipEntry</code> object for the specified
  375. * entry name.
  376. *
  377. * @param name the ZIP file entry name
  378. * @return the ZipEntry just created
  379. */
  380. protected ZipEntry createZipEntry(String name) {
  381. return new ZipEntry(name);
  382. }
  383.  
  384. /*
  385. * Reads end of deflated entry as well as EXT descriptor if present.
  386. */
  387. private void readEnd(ZipEntry e) throws IOException {
  388. int n = inf.getRemaining();
  389. if (n > 0) {
  390. ((PushbackInputStream)in).unread(buf, len - n, n);
  391. }
  392. if ((flag & 8) == 8) {
  393. /* "Data Descriptor" present */
  394. readFully(tmpbuf, 0, EXTHDR);
  395. long sig = get32(tmpbuf, 0);
  396. if (sig != EXTSIG) { // no EXTSIG present
  397. e.crc = sig;
  398. e.csize = get32(tmpbuf, EXTSIZ - EXTCRC);
  399. e.size = get32(tmpbuf, EXTLEN - EXTCRC);
  400. ((PushbackInputStream)in).unread(
  401. tmpbuf, EXTHDR - EXTCRC - 1, EXTCRC);
  402. } else {
  403. e.crc = get32(tmpbuf, EXTCRC);
  404. e.csize = get32(tmpbuf, EXTSIZ);
  405. e.size = get32(tmpbuf, EXTLEN);
  406. }
  407. }
  408. if (e.size != inf.getBytesWritten()) {
  409. throw new ZipException(
  410. "invalid entry size (expected " + e.size +
  411. " but got " + inf.getBytesWritten() + " bytes)");
  412. }
  413. if (e.csize != inf.getBytesRead()) {
  414. throw new ZipException(
  415. "invalid entry compressed size (expected " + e.csize +
  416. " but got " + inf.getBytesRead() + " bytes)");
  417. }
  418. if (e.crc != crc.getValue()) {
  419. throw new ZipException(
  420. "invalid entry CRC (expected 0x" + Long.toHexString(e.crc) +
  421. " but got 0x" + Long.toHexString(crc.getValue()) + ")");
  422. }
  423. }
  424.  
  425. /*
  426. * Reads bytes, blocking until all bytes are read.
  427. */
  428. private void readFully(byte[] b, int off, int len) throws IOException {
  429. while (len > 0) {
  430. int n = in.read(b, off, len);
  431. if (n == -1) {
  432. throw new EOFException();
  433. }
  434. off += n;
  435. len -= n;
  436. }
  437. }
  438.  
  439. /*
  440. * Fetches unsigned 16-bit value from byte array at specified offset.
  441. * The bytes are assumed to be in Intel (little-endian) byte order.
  442. */
  443. private static final int get16(byte b[], int off) {
  444. return (b[off] & 0xff) | ((b[off+1] & 0xff) << 8);
  445. }
  446.  
  447. /*
  448. * Fetches unsigned 32-bit value from byte array at specified offset.
  449. * The bytes are assumed to be in Intel (little-endian) byte order.
  450. */
  451. private static final long get32(byte b[], int off) {
  452. return get16(b, off) | ((long)get16(b, off+2) << 16);
  453. }
  454. }

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

ZipOutputStream.java:

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

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("Zip\u6587\u4EF6");
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("\u5F00\u59CB\u89E3\u538B\u7F29");
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();
}
}
}

  效果如图:

Java压缩包解压到指定文件的更多相关文章

  1. 把自解压的RAR压缩包解压到指定的软件安装目录

    原文 把自解压的RAR压缩包解压到指定的软件安装目录 今天千里独行同学给轻狂来信问了一个问题:如何把一个自解压的RAR压缩包解压到我们指定的软件安装目录.   其实,在NSIS中,我们可以灵活运用相关 ...

  2. 用tar命令把目标压缩包解压到指定位置

    linux下tar命令解压到指定的目录 : #tar zxvf /bbs.tar.zip -C /zzz/bbs    //把根目录下的bbs.tar.zip解压到/zzz/bbs下,前提要保证存在/ ...

  3. zend framework将zip格式的压缩文件导入并解压到指定文件

    html代码 <pre class="php" name="code"><fieldset> <legend>批量导入学生照 ...

  4. java 提取(解压)zip文件中特定后缀的文件并保存到指定目录

    内容简介 本文主要介绍使用ZipFile来提取zip压缩文件中特定后缀(如:png,jpg)的文件并保存到指定目录下. 导入包:import java.util.zip.ZipFile; 如需添加对r ...

  5. Java实现zip文件解压[到指定目录]

    2019独角兽企业重金招聘Python工程师标准>>> package com.ljheee.ziptool.core; import java.io.File; import ja ...

  6. java 提取(解压)rar文件中特定后缀的文件并保存到指定目录

    内容简介 本文主要介绍使用junrar来提取rar压缩文件中特定后缀(如:png,jpg)的文件并保存到指定目录下. 支持v4及以下版本压缩文件,不支持v5及以上. 在rar文件上右键,查看属性,在压 ...

  7. 《OD学hadoop》在LINUX下如何将tar压缩文件解压到指定的目录下

    linux下tar命令解压到指定的目录 :#tar zxvf /bbs.tar.zip -C /zzz/bbs //把根目录下的bbs.tar.zip解压到/zzz/bbs下,前提要保证存在/zzz/ ...

  8. Java动态解压zip压缩包

    import java.io.BufferedOutputStream; import java.io.File; import java.io.FileNotFoundException; impo ...

  9. tar 解压某个指定的文件或者文件夹

    1. 先查看压缩文档中有那些文件,如果都不清楚文件内容,然后就直接解压,这个是不可能的 使用#tar -tf 压缩包名称,可以查看压缩包内容 2.解压某个文件 tar -zxvf zabbix.tar ...

随机推荐

  1. 解决EasyUi中的DataGrid删除一条记录后,被删除的数据仍处于被选中状态问题

    项目中遇到这么一个问题,在easyui的datagrid中,删除一条记录成功,重新加载datagrid后,去点编辑操作,仍可把之前删除掉的那条记录进行编辑操作,正常情况应该是,删除后再去点击“编辑”, ...

  2. 基于octree的空间划分及搜索操作

    (1)  octree是一种用于管理稀疏3D数据的树形数据结构,每个内部节点都正好有八个子节点,介绍如何用octree在点云数据中进行空间划分及近邻搜索,实现“体素内近邻搜索(Neighbors wi ...

  3. Ubuntu下qemu环境搭建

    在查找资料过程中,发现自己搭建虚拟的arm环境的话,有一个比较好的软件就是qemu了,当然还有其他的,大家各投所好就好. 接下来说一下qemu环境搭建过程. 其实搭建很简单,作为小白,我还是捣鼓了两三 ...

  4. js dom 创建table标签和子属性, 以及创建多选框

    代码: <div class="Category"> <span id="Edit_headerTitle">Edit Categori ...

  5. Java如何处理异常层次结构?

    在Java编程中,如何处理异常层次结构? 以下是异常层次结构的示例图 - 此示例显示如何通过扩展Exception类来处理异常层次结构. package com.yiibai; class Anima ...

  6. Mybatis表关联一对多

    有了前面几章的基础,对一些简单的应用是可以处理的,但在实际项目中,经常是关联表的查询,比如:最常见到的多对一,一对多等.这些查询是如何处理的呢,这一讲就讲这个问题.前面几篇教程中介绍的都是单表映射的一 ...

  7. 于erlang依赖的linux调优

    [皇室]杭州-sunface(61087682) 上午 9:42:02 http://docs.basho.com/riak/latest/ops/tuning/linux/ 这篇文章对于erlang ...

  8. 【转】Castle Windsor之组件注册

    [转]Castle Windsor之组件注册 注册方式较多,大体有这么几种,学习得比较粗浅,先记录: 1.逐个注册组件 即对每个接口通过代码指定其实现类,代码: container.Register( ...

  9. Castle.Windsor依赖注入的高级应用_Castle.Windsor.3.1.0

    [转]Castle.Windsor依赖注入的高级应用_Castle.Windsor.3.1.0 1. 使用代码方式进行组件注册[依赖服务类] using System; using System.Co ...

  10. C# 判断一个字符串是否为url

    /// <summary> /// 判断一个字符串是否为url /// </summary> /// <param name="str">< ...