zip4j -- Java处理zip压缩文件的完整解决方案

xiaoxiao2021-02-28  79

转自 http://blog.csdn.net/zhyh1986/article/details/7921376

之前偶然有个需求相关压缩类的,搜到了这篇文章,看后觉得不错,就顺手记录下来,感谢原作者。

zip4j现在有新版本了(1.3.2版本),好久没有关注了,今天看了一下官网才发现1.3.2版本已经发布一年多了。

下载地址:http://download.csdn.net/detail/zhangyihui1986/8343773

本资源没有再设置下载积分,希望对大家有所帮助。

前言

一个多月前,因项目需要对Java语言下的zip格式压缩文件的处理作了一些了解,尝试了多种开源项目并写了几篇博客做记录:

http://blog.csdn.net/zhangyihui1986/article/details/7724229http://blog.csdn.net/zhangyihui1986/article/details/7723649http://blog.csdn.net/zhangyihui1986/article/details/7724616

 ZIP4J,作为解决了我的问题的终极解决方案,本来一开始在搜索引擎上就看到了它的踪迹,但因天朝的网络环境问题,zip4j的官网一直无法访问,最终使我多走了好多冤枉路,期间试过JDK的zip包,试过Apache的zip解决方案,也试过如winzipaes等其它的开源框架,最终没有满足自己的需求,最后,我不得已挂了一下代理将zip4j下载了下来,试用了一下,果然威力无比,所到之处所向披靡...

闲话少说,如果需要可以到zip4j的官网下载该开源项目:

http://www.lingala.net/zip4j/

不过需要提醒的是可能无法直接访问,如果无法正常访问,请自行准备代理访问,如果各位嫌麻烦,可以到这里下载:

http://download.csdn.net/detail/zhangyihui1986/4418509

这是我的资源链接,下载需要3分,您如果分数不多,可以留言索取,呵呵...我也需要积分,请谅解!

官网上下载的资源好像是不带API帮助文档的,我利用其源码生成了一份,也一并打在我的资源文件中,希望能帮到大家。

ZIP4J的官方说明

(自己翻译了一下,英文不好,呵呵...)

Key features(主要特性):

Create, Add, Extract, Update, Remove files from a Zip file 针对ZIP压缩文件创建、添加、抽出、更新和移除文件Read/Write password protected Zip files (读写有密码保护的Zip文件)Supports AES 128/256 Encryption (支持AES 128/256算法加密)Supports Standard Zip Encryption (支持标准Zip算法加密)Supports Zip64 format (支持zip64格式)Supports Store (No Compression) and Deflate compression method (支持Store(非压缩)和Deflate压缩方法---不太明白)Create or extract files from Split Zip files (Ex: z01, z02,...zip) (针对分块zip文件创建和抽出文件)Supports Unicode file names (支持Unicode编码文件名)Progress Monitor (进度监控)

从上面的主要特性可以看出,zip4j的功能是非常强大的,完全可以利用其写个类似于好压的zip文件管理软件,但我们用地最多的可能还是利用其作一些简单的解压和压缩操作,其它的功能极少触碰,我也一样,呵呵...

使用注意点

zip4j默认采用UTF-8编码,所以它支持中文,同时也支持密码,而且支持多种压缩算法,可以说功能强大,但使用起来却非常简单,当然,如果需求比较复杂,那就得好好去研究了。如果你仅仅是简单地解压一个zip压缩文件,那么只需要简单地几步即可:

[java]  view plain  copy public static void unzip(File zipFile, String dest, String passwd) throws ZipException {             ZipFile zFile = new ZipFile(zipFile);  // 首先创建ZipFile指向磁盘上的.zip文件             zFile.setFileNameCharset("GBK");       // 设置文件名编码,在GBK系统中需要设置             if (!zFile.isValidZipFile()) {   // 验证.zip文件是否合法,包括文件是否存在、是否为zip文件、是否被损坏等                 throw new ZipException("压缩文件不合法,可能被损坏.");             }             File destDir = new File(dest);     // 解压目录             if (destDir.isDirectory() && !destDir.exists()) {                 destDir.mkdir();             }             if (zFile.isEncrypted()) {                 zFile.setPassword(passwd.toCharArray());  // 设置密码             }             zFile.extractAll(dest);      // 将文件抽出到解压目录(解压)         }    

 当然将指定文件压缩成zip文件也是非常简单的事,此处不再贴代码,如有需要请参看下面的完整示例。

 提示:如果将要解压的压缩文件中的文件名含有中文,解压时需要注意一点,就是设置文件名字符集方法

[java]  view plain  copy zFile.setFileNameCharset("GBK");   

这个方法的调用一定要靠前,要靠多前呢?其实最好在创建ZipFile之后就设置上,至少要在

[java]  view plain  copy zFile.isValidZipFile()    

这个方法调用之前调用,我在应用时因为这个问题耽误好久,最后查看源码才弄明白,好像是ZipFile在验证方法中就将编码设置好,以后就不再对文件名编码作改变了。

完整示例

下面提供一个自己写的例子,鄙人才疏学浅,天分也差,写的代码质量很差,斗胆贴上,希望能起到抛砖引玉的作用。

[java]  view plain  copy package com.ninemax.cul.util;      import java.io.File;   import java.util.ArrayList;   import java.util.Collections;   import java.util.List;      import org.apache.commons.lang3.StringUtils;      import net.lingala.zip4j.core.ZipFile;   import net.lingala.zip4j.exception.ZipException;   import net.lingala.zip4j.model.FileHeader;   import net.lingala.zip4j.model.ZipParameters;   import net.lingala.zip4j.util.Zip4jConstants;      /**   * ZIP压缩文件操作工具类   * 支持密码   * 依赖zip4j开源项目(http://www.lingala.net/zip4j/)   * 版本1.3.1   * @author ninemax   */   public class CompressUtil {              /**       * 使用给定密码解压指定的ZIP压缩文件到指定目录       * <p>       * 如果指定目录不存在,可以自动创建,不合法的路径将导致异常被抛出       * @param zip 指定的ZIP压缩文件       * @param dest 解压目录       * @param passwd ZIP文件的密码       * @return 解压后文件数组       * @throws ZipException 压缩文件有损坏或者解压缩失败抛出       */       public static File [] unzip(String zip, String dest, String passwd) throws ZipException {           File zipFile = new File(zip);           return unzip(zipFile, dest, passwd);       }              /**       * 使用给定密码解压指定的ZIP压缩文件到当前目录       * @param zip 指定的ZIP压缩文件       * @param passwd ZIP文件的密码       * @return  解压后文件数组       * @throws ZipException 压缩文件有损坏或者解压缩失败抛出       */       public static File [] unzip(String zip, String passwd) throws ZipException {           File zipFile = new File(zip);           File parentDir = zipFile.getParentFile();           return unzip(zipFile, parentDir.getAbsolutePath(), passwd);       }              /**       * 使用给定密码解压指定的ZIP压缩文件到指定目录       * <p>       * 如果指定目录不存在,可以自动创建,不合法的路径将导致异常被抛出       * @param zip 指定的ZIP压缩文件       * @param dest 解压目录       * @param passwd ZIP文件的密码       * @return  解压后文件数组       * @throws ZipException 压缩文件有损坏或者解压缩失败抛出       */       public static File [] unzip(File zipFile, String dest, String passwd) throws ZipException {           ZipFile zFile = new ZipFile(zipFile);           zFile.setFileNameCharset("GBK");           if (!zFile.isValidZipFile()) {               throw new ZipException("压缩文件不合法,可能被损坏.");           }           File destDir = new File(dest);           if (destDir.isDirectory() && !destDir.exists()) {               destDir.mkdir();           }           if (zFile.isEncrypted()) {               zFile.setPassword(passwd.toCharArray());           }           zFile.extractAll(dest);                      List<FileHeader> headerList = zFile.getFileHeaders();           List<File> extractedFileList = new ArrayList<File>();           for(FileHeader fileHeader : headerList) {               if (!fileHeader.isDirectory()) {                   extractedFileList.add(new File(destDir,fileHeader.getFileName()));               }           }           File [] extractedFiles = new File[extractedFileList.size()];           extractedFileList.toArray(extractedFiles);           return extractedFiles;       }              /**       * 压缩指定文件到当前文件夹       * @param src 要压缩的指定文件       * @return 最终的压缩文件存放的绝对路径,如果为null则说明压缩失败.       */       public static String zip(String src) {           return zip(src,null);       }              /**       * 使用给定密码压缩指定文件或文件夹到当前目录       * @param src 要压缩的文件       * @param passwd 压缩使用的密码       * @return 最终的压缩文件存放的绝对路径,如果为null则说明压缩失败.       */       public static String zip(String src, String passwd) {           return zip(src, null, passwd);       }              /**       * 使用给定密码压缩指定文件或文件夹到当前目录       * @param src 要压缩的文件       * @param dest 压缩文件存放路径       * @param passwd 压缩使用的密码       * @return 最终的压缩文件存放的绝对路径,如果为null则说明压缩失败.       */       public static String zip(String src, String dest, String passwd) {           return zip(src, dest, true, passwd);       }              /**       * 使用给定密码压缩指定文件或文件夹到指定位置.       * <p>       * dest可传最终压缩文件存放的绝对路径,也可以传存放目录,也可以传null或者"".<br />       * 如果传null或者""则将压缩文件存放在当前目录,即跟源文件同目录,压缩文件名取源文件名,以.zip为后缀;<br />       * 如果以路径分隔符(File.separator)结尾,则视为目录,压缩文件名取源文件名,以.zip为后缀,否则视为文件名.       * @param src 要压缩的文件或文件夹路径       * @param dest 压缩文件存放路径       * @param isCreateDir 是否在压缩文件里创建目录,仅在压缩文件为目录时有效.<br />       * 如果为false,将直接压缩目录下文件到压缩文件.       * @param passwd 压缩使用的密码       * @return 最终的压缩文件存放的绝对路径,如果为null则说明压缩失败.       */       public static String zip(String src, String dest, boolean isCreateDir, String passwd) {           File srcFile = new File(src);           dest = buildDestinationZipFilePath(srcFile, dest);           ZipParameters parameters = new ZipParameters();           parameters.setCompressionMethod(Zip4jConstants.COMP_DEFLATE);           // 压缩方式           parameters.setCompressionLevel(Zip4jConstants.DEFLATE_LEVEL_NORMAL);    // 压缩级别           if (!StringUtils.isEmpty(passwd)) {               parameters.setEncryptFiles(true);               parameters.setEncryptionMethod(Zip4jConstants.ENC_METHOD_STANDARD); // 加密方式               parameters.setPassword(passwd.toCharArray());           }           try {               ZipFile zipFile = new ZipFile(dest);               if (srcFile.isDirectory()) {                   // 如果不创建目录的话,将直接把给定目录下的文件压缩到压缩文件,即没有目录结构                   if (!isCreateDir) {                       File [] subFiles = srcFile.listFiles();                       ArrayList<File> temp = new ArrayList<File>();                       Collections.addAll(temp, subFiles);                       zipFile.addFiles(temp, parameters);                       return dest;                   }                   zipFile.addFolder(srcFile, parameters);               } else {                   zipFile.addFile(srcFile, parameters);               }               return dest;           } catch (ZipException e) {               e.printStackTrace();           }           return null;       }              /**       * 构建压缩文件存放路径,如果不存在将会创建       * 传入的可能是文件名或者目录,也可能不传,此方法用以转换最终压缩文件的存放路径       * @param srcFile 源文件       * @param destParam 压缩目标路径       * @return 正确的压缩文件存放路径       */       private static String buildDestinationZipFilePath(File srcFile,String destParam) {           if (StringUtils.isEmpty(destParam)) {               if (srcFile.isDirectory()) {                   destParam = srcFile.getParent() + File.separator + srcFile.getName() + ".zip";               } else {                   String fileName = srcFile.getName().substring(0, srcFile.getName().lastIndexOf("."));                   destParam = srcFile.getParent() + File.separator + fileName + ".zip";               }           } else {               createDestDirectoryIfNecessary(destParam);  // 在指定路径不存在的情况下将其创建出来               if (destParam.endsWith(File.separator)) {                   String fileName = "";                   if (srcFile.isDirectory()) {                       fileName = srcFile.getName();                   } else {                       fileName = srcFile.getName().substring(0, srcFile.getName().lastIndexOf("."));                   }                   destParam += fileName + ".zip";               }           }           return destParam;       }              /**       * 在必要的情况下创建压缩文件存放目录,比如指定的存放路径并没有被创建       * @param destParam 指定的存放路径,有可能该路径并没有被创建       */       private static void createDestDirectoryIfNecessary(String destParam) {           File destDir = null;           if (destParam.endsWith(File.separator)) {               destDir = new File(destParam);           } else {               destDir = new File(destParam.substring(0, destParam.lastIndexOf(File.separator)));           }           if (!destDir.exists()) {               destDir.mkdirs();           }       }          public static void main(String[] args) {           zip("d:\\test\\cc""d:\\test\\cc.zip""11");   //      try {   //          File[] files = unzip("d:\\test\\汉字.zip", "aa");   //          for (int i = 0; i < files.length; i++) {   //              System.out.println(files[i]);   //          }   //      } catch (ZipException e) {   //          e.printStackTrace();   //      }       }   }  

需要学习的东西太多,没太多时间(或许只是借口)去研究它,上面的例子仅是简单地解压和压缩操作;但在使用中可以发现Zip4J功能比较完备,如果需要更多地支持,那就真要好好去研究一下它,也许它真的不会使您失望。。。

补充

删除压缩文件中的目录

看到有朋友在问如何删除压缩文件中的目录,在这里补充一下。

利用zip4j删除压缩文件中的目录,查阅API后很容易想到这样的方式:

[java]  view plain  copy ZipFile zipFile = new ZipFile("d:\\FeiQ-V2.5.zip");   zipFile.setFileNameCharset("GBK");   zipFile.removeFile("sounds/");      // sounds是zip文件中的一个目录  

但这种直接删除压缩文件中非空目录的方式是不会成功的,你会看到zip文件丝毫没有变化,虽然目录对应的FileHeader已被删除(表现就是如果这时再将目录下的所有文件删除,则该目录随之消失) ;因此我们需要将该目录下所有的文件都删除掉,最后再将目录删除,根据这个思路,我们很容易形成如下的代码:

[java]  view plain  copy void removeDirFromZipArchive(String file, String removeDir) throws ZipException {       // 创建ZipFile并设置编码       ZipFile zipFile = new ZipFile(file);       zipFile.setFileNameCharset("GBK");              // 给要删除的目录加上路径分隔符       if (!removeDir.endsWith(File.separator)) removeDir += File.separator;          // 如果目录不存在, 直接返回       FileHeader dirHeader = zipFile.getFileHeader(removeDir);       if (null == dirHeader) return;          // 遍历压缩文件中所有的FileHeader, 将指定删除目录下的子文件删除       List allHeaders = zipFile.getFileHeaders();       for(int i=0, len = allHeaders.size(); i<len; i++) {           FileHeader subHeader = (FileHeader) allHeaders.get(i);           if (subHeader.getFileName().startsWith(dirHeader.getFileName())                   && !subHeader.getFileName().equals(dirHeader.getFileName())) {               zipFile.removeFile(subHeader);           }       }       // 最后删除指定目录       zipFile.removeFile(dirHeader);   }  

这样仍然解决不了问题,如果你这样做了,那么你将会得到一个java.lang.IndexOutOfBoundsException异常,那么看似正常的代码为什么会报索引越界异常呢?其实我们通过zipFile.getFileHeaders()方法得到的List会随遍历中的删除操作而发生变化,也就是说我们删除了某个FileHeader,将会反映到该List中。每成功删除一个FileHeader,List长度就减1,而i一直在0至List的初始长度之间递增,反复几次后就可能出现越界异常。

为了避免这种情况发生,我们可以多做一些操作,比如可以在遍历中暂不进行删除操作,而只是将要删除的文件记录下来,遍历结束后再统一删除,最后将目录删除,经测试,这个思路可以解决问题。

简单示例代码:

[java]  view plain  copy void removeDirFromZipArchive(String file, String removeDir) throws ZipException {       // 创建ZipFile并设置编码       ZipFile zipFile = new ZipFile(file);       zipFile.setFileNameCharset("GBK");              // 给要删除的目录加上路径分隔符       if (!removeDir.endsWith(File.separator)) removeDir += File.separator;              // 如果目录不存在, 直接返回       FileHeader dirHeader = zipFile.getFileHeader(removeDir);       if (null == dirHeader) return;          // 遍历压缩文件中所有的FileHeader, 将指定删除目录下的子文件名保存起来       List headersList = zipFile.getFileHeaders();       List<String> removeHeaderNames = new ArrayList<String>();       for(int i=0, len = headersList.size(); i<len; i++) {           FileHeader subHeader = (FileHeader) headersList.get(i);           if (subHeader.getFileName().startsWith(dirHeader.getFileName())                   && !subHeader.getFileName().equals(dirHeader.getFileName())) {               removeHeaderNames.add(subHeader.getFileName());           }       }       // 遍历删除指定目录下的所有子文件, 最后删除指定目录(此时已为空目录)       for(String headerNameString : removeHeaderNames) {           zipFile.removeFile(headerNameString);       }       zipFile.removeFile(dirHeader);   }  

也许还有其它的办法来解决此问题,如果您有需要,就留待您来解决了。

zip4j现在有新版本了(1.3.2版本),好久没有关注了,今天看了一下官网才发现1.3.2版本已经发布一年多了。

下载地址:http://download.csdn.net/detail/zhangyihui1986/8343773

本资源没有再设置下载积分,希望对大家有所帮助。

前言

一个多月前,因项目需要对Java语言下的zip格式压缩文件的处理作了一些了解,尝试了多种开源项目并写了几篇博客做记录:

http://blog.csdn.net/zhangyihui1986/article/details/7724229http://blog.csdn.net/zhangyihui1986/article/details/7723649http://blog.csdn.net/zhangyihui1986/article/details/7724616

 ZIP4J,作为解决了我的问题的终极解决方案,本来一开始在搜索引擎上就看到了它的踪迹,但因天朝的网络环境问题,zip4j的官网一直无法访问,最终使我多走了好多冤枉路,期间试过JDK的zip包,试过Apache的zip解决方案,也试过如winzipaes等其它的开源框架,最终没有满足自己的需求,最后,我不得已挂了一下代理将zip4j下载了下来,试用了一下,果然威力无比,所到之处所向披靡...

闲话少说,如果需要可以到zip4j的官网下载该开源项目:

http://www.lingala.net/zip4j/

不过需要提醒的是可能无法直接访问,如果无法正常访问,请自行准备代理访问,如果各位嫌麻烦,可以到这里下载:

http://download.csdn.net/detail/zhangyihui1986/4418509

这是我的资源链接,下载需要3分,您如果分数不多,可以留言索取,呵呵...我也需要积分,请谅解!

官网上下载的资源好像是不带API帮助文档的,我利用其源码生成了一份,也一并打在我的资源文件中,希望能帮到大家。

ZIP4J的官方说明

(自己翻译了一下,英文不好,呵呵...)

Key features(主要特性):

Create, Add, Extract, Update, Remove files from a Zip file 针对ZIP压缩文件创建、添加、抽出、更新和移除文件Read/Write password protected Zip files (读写有密码保护的Zip文件)Supports AES 128/256 Encryption (支持AES 128/256算法加密)Supports Standard Zip Encryption (支持标准Zip算法加密)Supports Zip64 format (支持zip64格式)Supports Store (No Compression) and Deflate compression method (支持Store(非压缩)和Deflate压缩方法---不太明白)Create or extract files from Split Zip files (Ex: z01, z02,...zip) (针对分块zip文件创建和抽出文件)Supports Unicode file names (支持Unicode编码文件名)Progress Monitor (进度监控)

从上面的主要特性可以看出,zip4j的功能是非常强大的,完全可以利用其写个类似于好压的zip文件管理软件,但我们用地最多的可能还是利用其作一些简单的解压和压缩操作,其它的功能极少触碰,我也一样,呵呵...

使用注意点

zip4j默认采用UTF-8编码,所以它支持中文,同时也支持密码,而且支持多种压缩算法,可以说功能强大,但使用起来却非常简单,当然,如果需求比较复杂,那就得好好去研究了。如果你仅仅是简单地解压一个zip压缩文件,那么只需要简单地几步即可:

[java]  view plain  copy public static void unzip(File zipFile, String dest, String passwd) throws ZipException {             ZipFile zFile = new ZipFile(zipFile);  // 首先创建ZipFile指向磁盘上的.zip文件             zFile.setFileNameCharset("GBK");       // 设置文件名编码,在GBK系统中需要设置             if (!zFile.isValidZipFile()) {   // 验证.zip文件是否合法,包括文件是否存在、是否为zip文件、是否被损坏等                 throw new ZipException("压缩文件不合法,可能被损坏.");             }             File destDir = new File(dest);     // 解压目录             if (destDir.isDirectory() && !destDir.exists()) {                 destDir.mkdir();             }             if (zFile.isEncrypted()) {                 zFile.setPassword(passwd.toCharArray());  // 设置密码             }             zFile.extractAll(dest);      // 将文件抽出到解压目录(解压)         }    

 当然将指定文件压缩成zip文件也是非常简单的事,此处不再贴代码,如有需要请参看下面的完整示例。

 提示:如果将要解压的压缩文件中的文件名含有中文,解压时需要注意一点,就是设置文件名字符集方法

[java]  view plain  copy zFile.setFileNameCharset("GBK");   

这个方法的调用一定要靠前,要靠多前呢?其实最好在创建ZipFile之后就设置上,至少要在

[java]  view plain  copy zFile.isValidZipFile()    

这个方法调用之前调用,我在应用时因为这个问题耽误好久,最后查看源码才弄明白,好像是ZipFile在验证方法中就将编码设置好,以后就不再对文件名编码作改变了。

完整示例

下面提供一个自己写的例子,鄙人才疏学浅,天分也差,写的代码质量很差,斗胆贴上,希望能起到抛砖引玉的作用。

[java]  view plain  copy package com.ninemax.cul.util;      import java.io.File;   import java.util.ArrayList;   import java.util.Collections;   import java.util.List;      import org.apache.commons.lang3.StringUtils;      import net.lingala.zip4j.core.ZipFile;   import net.lingala.zip4j.exception.ZipException;   import net.lingala.zip4j.model.FileHeader;   import net.lingala.zip4j.model.ZipParameters;   import net.lingala.zip4j.util.Zip4jConstants;      /**   * ZIP压缩文件操作工具类   * 支持密码   * 依赖zip4j开源项目(http://www.lingala.net/zip4j/)   * 版本1.3.1   * @author ninemax   */   public class CompressUtil {              /**       * 使用给定密码解压指定的ZIP压缩文件到指定目录       * <p>       * 如果指定目录不存在,可以自动创建,不合法的路径将导致异常被抛出       * @param zip 指定的ZIP压缩文件       * @param dest 解压目录       * @param passwd ZIP文件的密码       * @return 解压后文件数组       * @throws ZipException 压缩文件有损坏或者解压缩失败抛出       */       public static File [] unzip(String zip, String dest, String passwd) throws ZipException {           File zipFile = new File(zip);           return unzip(zipFile, dest, passwd);       }              /**       * 使用给定密码解压指定的ZIP压缩文件到当前目录       * @param zip 指定的ZIP压缩文件       * @param passwd ZIP文件的密码       * @return  解压后文件数组       * @throws ZipException 压缩文件有损坏或者解压缩失败抛出       */       public static File [] unzip(String zip, String passwd) throws ZipException {           File zipFile = new File(zip);           File parentDir = zipFile.getParentFile();           return unzip(zipFile, parentDir.getAbsolutePath(), passwd);       }              /**       * 使用给定密码解压指定的ZIP压缩文件到指定目录       * <p>       * 如果指定目录不存在,可以自动创建,不合法的路径将导致异常被抛出       * @param zip 指定的ZIP压缩文件       * @param dest 解压目录       * @param passwd ZIP文件的密码       * @return  解压后文件数组       * @throws ZipException 压缩文件有损坏或者解压缩失败抛出       */       public static File [] unzip(File zipFile, String dest, String passwd) throws ZipException {           ZipFile zFile = new ZipFile(zipFile);           zFile.setFileNameCharset("GBK");           if (!zFile.isValidZipFile()) {               throw new ZipException("压缩文件不合法,可能被损坏.");           }           File destDir = new File(dest);           if (destDir.isDirectory() && !destDir.exists()) {               destDir.mkdir();           }           if (zFile.isEncrypted()) {               zFile.setPassword(passwd.toCharArray());           }           zFile.extractAll(dest);                      List<FileHeader> headerList = zFile.getFileHeaders();           List<File> extractedFileList = new ArrayList<File>();           for(FileHeader fileHeader : headerList) {               if (!fileHeader.isDirectory()) {                   extractedFileList.add(new File(destDir,fileHeader.getFileName()));               }           }           File [] extractedFiles = new File[extractedFileList.size()];           extractedFileList.toArray(extractedFiles);           return extractedFiles;       }              /**       * 压缩指定文件到当前文件夹       * @param src 要压缩的指定文件       * @return 最终的压缩文件存放的绝对路径,如果为null则说明压缩失败.       */       public static String zip(String src) {           return zip(src,null);       }              /**       * 使用给定密码压缩指定文件或文件夹到当前目录       * @param src 要压缩的文件       * @param passwd 压缩使用的密码       * @return 最终的压缩文件存放的绝对路径,如果为null则说明压缩失败.       */       public static String zip(String src, String passwd) {           return zip(src, null, passwd);       }              /**       * 使用给定密码压缩指定文件或文件夹到当前目录       * @param src 要压缩的文件       * @param dest 压缩文件存放路径       * @param passwd 压缩使用的密码       * @return 最终的压缩文件存放的绝对路径,如果为null则说明压缩失败.       */       public static String zip(String src, String dest, String passwd) {           return zip(src, dest, true, passwd);       }              /**       * 使用给定密码压缩指定文件或文件夹到指定位置.       * <p>       * dest可传最终压缩文件存放的绝对路径,也可以传存放目录,也可以传null或者"".<br />       * 如果传null或者""则将压缩文件存放在当前目录,即跟源文件同目录,压缩文件名取源文件名,以.zip为后缀;<br />       * 如果以路径分隔符(File.separator)结尾,则视为目录,压缩文件名取源文件名,以.zip为后缀,否则视为文件名.       * @param src 要压缩的文件或文件夹路径       * @param dest 压缩文件存放路径       * @param isCreateDir 是否在压缩文件里创建目录,仅在压缩文件为目录时有效.<br />       * 如果为false,将直接压缩目录下文件到压缩文件.       * @param passwd 压缩使用的密码       * @return 最终的压缩文件存放的绝对路径,如果为null则说明压缩失败.       */       public static String zip(String src, String dest, boolean isCreateDir, String passwd) {           File srcFile = new File(src);           dest = buildDestinationZipFilePath(srcFile, dest);           ZipParameters parameters = new ZipParameters();           parameters.setCompressionMethod(Zip4jConstants.COMP_DEFLATE);           // 压缩方式           parameters.setCompressionLevel(Zip4jConstants.DEFLATE_LEVEL_NORMAL);    // 压缩级别           if (!StringUtils.isEmpty(passwd)) {               parameters.setEncryptFiles(true);               parameters.setEncryptionMethod(Zip4jConstants.ENC_METHOD_STANDARD); // 加密方式               parameters.setPassword(passwd.toCharArray());           }           try {               ZipFile zipFile = new ZipFile(dest);               if (srcFile.isDirectory()) {                   // 如果不创建目录的话,将直接把给定目录下的文件压缩到压缩文件,即没有目录结构                   if (!isCreateDir) {                       File [] subFiles = srcFile.listFiles();                       ArrayList<File> temp = new ArrayList<File>();                       Collections.addAll(temp, subFiles);                       zipFile.addFiles(temp, parameters);                       return dest;                   }                   zipFile.addFolder(srcFile, parameters);               } else {                   zipFile.addFile(srcFile, parameters);               }               return dest;           } catch (ZipException e) {               e.printStackTrace();           }           return null;       }              /**       * 构建压缩文件存放路径,如果不存在将会创建       * 传入的可能是文件名或者目录,也可能不传,此方法用以转换最终压缩文件的存放路径       * @param srcFile 源文件       * @param destParam 压缩目标路径       * @return 正确的压缩文件存放路径       */       private static String buildDestinationZipFilePath(File srcFile,String destParam) {           if (StringUtils.isEmpty(destParam)) {               if (srcFile.isDirectory()) {                   destParam = srcFile.getParent() + File.separator + srcFile.getName() + ".zip";               } else {                   String fileName = srcFile.getName().substring(0, srcFile.getName().lastIndexOf("."));                   destParam = srcFile.getParent() + File.separator + fileName + ".zip";               }           } else {               createDestDirectoryIfNecessary(destParam);  // 在指定路径不存在的情况下将其创建出来               if (destParam.endsWith(File.separator)) {                   String fileName = "";                   if (srcFile.isDirectory()) {                       fileName = srcFile.getName();                   } else {                       fileName = srcFile.getName().substring(0, srcFile.getName().lastIndexOf("."));                   }                   destParam += fileName + ".zip";               }           }           return destParam;       }              /**       * 在必要的情况下创建压缩文件存放目录,比如指定的存放路径并没有被创建       * @param destParam 指定的存放路径,有可能该路径并没有被创建       */       private static void createDestDirectoryIfNecessary(String destParam) {           File destDir = null;           if (destParam.endsWith(File.separator)) {               destDir = new File(destParam);           } else {               destDir = new File(destParam.substring(0, destParam.lastIndexOf(File.separator)));           }           if (!destDir.exists()) {               destDir.mkdirs();           }       }          public static void main(String[] args) {           zip("d:\\test\\cc""d:\\test\\cc.zip""11");   //      try {   //          File[] files = unzip("d:\\test\\汉字.zip", "aa");   //          for (int i = 0; i < files.length; i++) {   //              System.out.println(files[i]);   //          }   //      } catch (ZipException e) {   //          e.printStackTrace();   //      }       }   }  

需要学习的东西太多,没太多时间(或许只是借口)去研究它,上面的例子仅是简单地解压和压缩操作;但在使用中可以发现Zip4J功能比较完备,如果需要更多地支持,那就真要好好去研究一下它,也许它真的不会使您失望。。。

补充

删除压缩文件中的目录

看到有朋友在问如何删除压缩文件中的目录,在这里补充一下。

利用zip4j删除压缩文件中的目录,查阅API后很容易想到这样的方式:

[java]  view plain  copy ZipFile zipFile = new ZipFile("d:\\FeiQ-V2.5.zip");   zipFile.setFileNameCharset("GBK");   zipFile.removeFile("sounds/");      // sounds是zip文件中的一个目录  

但这种直接删除压缩文件中非空目录的方式是不会成功的,你会看到zip文件丝毫没有变化,虽然目录对应的FileHeader已被删除(表现就是如果这时再将目录下的所有文件删除,则该目录随之消失) ;因此我们需要将该目录下所有的文件都删除掉,最后再将目录删除,根据这个思路,我们很容易形成如下的代码:

[java]  view plain  copy void removeDirFromZipArchive(String file, String removeDir) throws ZipException {       // 创建ZipFile并设置编码       ZipFile zipFile = new ZipFile(file);       zipFile.setFileNameCharset("GBK");              // 给要删除的目录加上路径分隔符       if (!removeDir.endsWith(File.separator)) removeDir += File.separator;          // 如果目录不存在, 直接返回       FileHeader dirHeader = zipFile.getFileHeader(removeDir);       if (null == dirHeader) return;          // 遍历压缩文件中所有的FileHeader, 将指定删除目录下的子文件删除       List allHeaders = zipFile.getFileHeaders();       for(int i=0, len = allHeaders.size(); i<len; i++) {           FileHeader subHeader = (FileHeader) allHeaders.get(i);           if (subHeader.getFileName().startsWith(dirHeader.getFileName())                   && !subHeader.getFileName().equals(dirHeader.getFileName())) {               zipFile.removeFile(subHeader);           }       }       // 最后删除指定目录       zipFile.removeFile(dirHeader);   }  

这样仍然解决不了问题,如果你这样做了,那么你将会得到一个java.lang.IndexOutOfBoundsException异常,那么看似正常的代码为什么会报索引越界异常呢?其实我们通过zipFile.getFileHeaders()方法得到的List会随遍历中的删除操作而发生变化,也就是说我们删除了某个FileHeader,将会反映到该List中。每成功删除一个FileHeader,List长度就减1,而i一直在0至List的初始长度之间递增,反复几次后就可能出现越界异常。

为了避免这种情况发生,我们可以多做一些操作,比如可以在遍历中暂不进行删除操作,而只是将要删除的文件记录下来,遍历结束后再统一删除,最后将目录删除,经测试,这个思路可以解决问题。

简单示例代码:

[java]  view plain  copy void removeDirFromZipArchive(String file, String removeDir) throws ZipException {       // 创建ZipFile并设置编码       ZipFile zipFile = new ZipFile(file);       zipFile.setFileNameCharset("GBK");              // 给要删除的目录加上路径分隔符       if (!removeDir.endsWith(File.separator)) removeDir += File.separator;              // 如果目录不存在, 直接返回       FileHeader dirHeader = zipFile.getFileHeader(removeDir);       if (null == dirHeader) return;          // 遍历压缩文件中所有的FileHeader, 将指定删除目录下的子文件名保存起来       List headersList = zipFile.getFileHeaders();       List<String> removeHeaderNames = new ArrayList<String>();       for(int i=0, len = headersList.size(); i<len; i++) {           FileHeader subHeader = (FileHeader) headersList.get(i);           if (subHeader.getFileName().startsWith(dirHeader.getFileName())                   && !subHeader.getFileName().equals(dirHeader.getFileName())) {               removeHeaderNames.add(subHeader.getFileName());           }       }       // 遍历删除指定目录下的所有子文件, 最后删除指定目录(此时已为空目录)       for(String headerNameString : removeHeaderNames) {           zipFile.removeFile(headerNameString);       }       zipFile.removeFile(dirHeader);   }  

也许还有其它的办法来解决此问题,如果您有需要,就留待您来解决了。

转载请注明原文地址: https://www.6miu.com/read-79719.html

最新回复(0)