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

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

有了上面那两个类后,我们就不用java.util.zip包下的这两个类来做压缩,而是用来面的修改后的类来做,我写了一个简单的测试程序如下:

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

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

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

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

java压缩文件,中文问题相关推荐

  1. java 压缩 乱码_如何解决java压缩文件乱码问题

    用java来打包文件生成压缩文件,有两个地方会出现乱码: 内容的中文乱码问题:修改sun的源码.使用开源的类库org.apache.tools.zip.ZipOutputStream和org.apac ...

  2. java压缩文件读取_用Java读取/写入压缩和非压缩文件

    java压缩文件读取 这篇文章的主要原因是尝试不要重复自己( DRY ),因为通常,我会遇到递归的需求,即读写压缩的和非压缩的文件(主要是JSON和CSV). 首先让我们看看如何读取文本文件. 注意我 ...

  3. java.util.zip 用法,Java压缩文件工具类ZipUtil使用方法代码示例

    本文实例通过Java的Zip输入输出流实现压缩和解压文件,前一部分代码实现获取文件路径,压缩文件名的更改等,具体如下: package com.utility.zip; import java.io. ...

  4. java压缩文件耗时:30秒到1秒的优化过程

    点击上方蓝字关注我们 有一个需求需要将前端传过来的10张照片,然后后端进行处理以后压缩成一个压缩包通过网络流传输出去.之前没有接触过用Java压缩文件的,所以就直接上网找了一个例子改了一下用了,改完以 ...

  5. java压缩文件,并对压缩包添加解压密码

    java压缩文件,并对压缩包添加解压密码 java自带的java.util.zip包只能压缩文件,不能对压缩包添加解压密码,添加解压密码需要借助第三方工具,目前最好用的是zip4j工具包,其api操作 ...

  6. linux下解压缩文件中文乱码问题的解决

    在windows上压缩的文件,是以系统默认编码中文来压缩文件.由于zip文件中没有声明其编码,所以linux上的unzip一般以默认编码解压,中文文件名会出现乱码. 虽然2005年就有人把这报告为bu ...

  7. 一个撇脚的java压缩文件工具类

    今天弄里一个压缩文件的工具类,功能不是很完善,只支持压缩后单级目录,二级文件夹的文件名好像只能用中文,并且解压后还是乱码.请各位高手大侠批评指教,不胜感激! package tests; import ...

  8. java压缩文件,在线下载文件并压缩

    2019独角兽企业重金招聘Python工程师标准>>> 压缩本地文件 import java.io.*; import java.net.HttpURLConnection; imp ...

  9. java压缩文件详解_Java解压和压缩带密码的zip文件过程详解

    前言 JDK自带的ZIP操作接口(java.util.zip包,请参看文章末尾的博客链接)并不支持密码,甚至也不支持中文文件名. 为了解决ZIP压缩文件的密码问题,在网上搜索良久,终于找到了winzi ...

最新文章

  1. 云解析DNS产品优势与应用场景
  2. Android新权限机制 AppOps
  3. java迭代器 异常_java.util.NoSuchElementException在Java中使用迭代器
  4. c语言开发 .c .h,求助C语言大佬 , 只会写到一个.c文件里 ,不会用.h头文件
  5. 如何在Windows上使用Git创建一个可执行脚本?
  6. sqlmap地表最强sql注入检测工具学习使用
  7. oracle数据库从入门到精通
  8. 高通CEO:已向美国申请向华为出售芯片 但尚未有回应
  9. Sql Server 从日志中恢复误删除或误Update的数据
  10. HDU2030 汉字统计【入门】
  11. appassembler-maven-plugin插件打包本地依赖的jar
  12. mobile 部署和/或注册失败 0x8973190e 解决办法
  13. 尔雅 科学通史(吴国盛) 个人笔记及课后习题 2018 第九章 科学、技术与工业
  14. 给定一段IP地址172.18.18.128/26,试为该网络做一个IP地址规划,要求开 发室1、开发室2以及制造部各为一个VLAN。
  15. vn.py源码解读(八、回测结果计算代码解析)
  16. 电脑电池出场容量与目前最大容量查询查询
  17. 使用dev-c++建立工程(多个文件一同编译连接)并运行
  18. u盘插到电脑计算机里没有反应,U盘插入电脑没有反应 怎么查看是哪里坏了?
  19. Sdwan关于视频监控
  20. wgt文件怎么安装到手机_安卓wgt安装

热门文章

  1. 分拣外观残缺的机器人_复合机器人AGV+协作机器人的应用领域
  2. python 保存图片代码_最简单的selenium+Python自动右键保存图片
  3. php smarty模板配置,Smarty模板简单配置与使用方法示例
  4. (一)Eureka搭建服务注册中心
  5. SpringCloud 入门教程(四): 分布式环境下自动发现配置服务
  6. 2020数字营销白皮书
  7. lisp 发凹圆角_css能实现这样的内凹圆角吗?如何实现?具体代码是!!
  8. 软件开发质量的双保险 — 3.应用设计验证与应用用例
  9. 【UML】UML扩展的建模概念
  10. 数列分段(洛谷P1181题题解,Java语言描述)