• java对zip、rar、7z文件带密码解压实例


    在一些日常业务中,会遇到一些琐碎文件需要统一打包到一个压缩包中上传,业务方在后台接收到压缩包后自行解压,然后解析相应文件。而且可能涉及安全保密,因此会在压缩时带上密码,要求后台业务可以指定密码进行解压。

    应用环境说明:jdk1.8,maven3.x,需要基于java语言实现对zip、rar、7z等常见压缩包的解压工作。

    首先关于zip和rar、7z等压缩工具和压缩算法就不在此赘述,下面通过一个数据对比,使用上述三种不同的压缩算法,采用默认的压缩方式,看到压缩的文件大小如下:

    转换成图表看得更直观,如下图:

    从以上图表可以看到,7z的压缩率是最高,而zip压缩率比较低,rar比zip稍微好点。单纯从压缩率看,7z>rar4>rar5>zip。

    下面具体说明在java中如何进行相应解压:

    1、pom.xml

    1. <project xmlns="http://maven.apache.org/POM/4.0.0"
    2. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    3. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    4. <modelVersion>4.0.0</modelVersion>
    5. <groupId>com.yelang</groupId>
    6. <artifactId>7zdemo</artifactId>
    7. <version>0.0.1-SNAPSHOT</version>
    8. <dependencies>
    9. <dependency>
    10. <groupId>net.lingala.zip4j</groupId>
    11. <artifactId>zip4j</artifactId>
    12. <version>2.9.0</version>
    13. </dependency>
    14. <dependency>
    15. <groupId>net.sf.sevenzipjbinding</groupId>
    16. <artifactId>sevenzipjbinding</artifactId>
    17. <version>16.02-2.01</version>
    18. </dependency>
    19. <dependency>
    20. <groupId>net.sf.sevenzipjbinding</groupId>
    21. <artifactId>sevenzipjbinding-all-platforms</artifactId>
    22. <version>16.02-2.01</version>
    23. </dependency>
    24. <dependency>
    25. <groupId>org.tukaani</groupId>
    26. <artifactId>xz</artifactId>
    27. <version>1.9</version>
    28. </dependency>
    29. <dependency>
    30. <groupId>org.apache.commons</groupId>
    31. <artifactId>commons-compress</artifactId>
    32. <version>1.21</version>
    33. </dependency>
    34. <!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
    35. <dependency>
    36. <groupId>org.slf4j</groupId>
    37. <artifactId>slf4j-api</artifactId>
    38. <version>1.7.30</version>
    39. </dependency>
    40. <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
    41. <dependency>
    42. <groupId>org.apache.commons</groupId>
    43. <artifactId>commons-lang3</artifactId>
    44. <version>3.12.0</version>
    45. </dependency>
    46. <!-- https://mvnrepository.com/artifact/fr.opensagres.xdocreport/xdocreport -->
    47. <dependency>
    48. <groupId>fr.opensagres.xdocreport</groupId>
    49. <artifactId>xdocreport</artifactId>
    50. <version>1.0.6</version>
    51. </dependency>
    52. </dependencies>
    53. </project>

    主要依赖的jar包有:zip4j、sevenzipjbinding等。

    2、zip解压

    1. @SuppressWarnings("resource")
    2. private static String unZip(String rootPath, String sourceRarPath, String destDirPath, String passWord) {
    3. ZipFile zipFile = null;
    4. String result = "";
    5. try {
    6. //String filePath = sourceRarPath;
    7. String filePath = rootPath + sourceRarPath;
    8. if (StringUtils.isNotBlank(passWord)) {
    9. zipFile = new ZipFile(filePath, passWord.toCharArray());
    10. } else {
    11. zipFile = new ZipFile(filePath);
    12. }
    13. zipFile.setCharset(Charset.forName("GBK"));
    14. zipFile.extractAll(rootPath + destDirPath);
    15. } catch (Exception e) {
    16. log.error("unZip error", e);
    17. return e.getMessage();
    18. }
    19. return result;
    20. }

    3、rar解压

    1. private static String unRar(String rootPath, String sourceRarPath, String destDirPath, String passWord) {
    2. String rarDir = rootPath + sourceRarPath;
    3. String outDir = rootPath + destDirPath + File.separator;
    4. RandomAccessFile randomAccessFile = null;
    5. IInArchive inArchive = null;
    6. try {
    7. // 第一个参数是需要解压的压缩包路径,第二个参数参考JdkAPI文档的RandomAccessFile
    8. randomAccessFile = new RandomAccessFile(rarDir, "r");
    9. if (StringUtils.isNotBlank(passWord))
    10. inArchive = SevenZip.openInArchive(null, new RandomAccessFileInStream(randomAccessFile), passWord);
    11. else
    12. inArchive = SevenZip.openInArchive(null, new RandomAccessFileInStream(randomAccessFile));
    13. ISimpleInArchive simpleInArchive = inArchive.getSimpleInterface();
    14. for (final ISimpleInArchiveItem item : simpleInArchive.getArchiveItems()) {
    15. final int[] hash = new int[]{0};
    16. if (!item.isFolder()) {
    17. ExtractOperationResult result;
    18. final long[] sizeArray = new long[1];
    19. File outFile = new File(outDir + item.getPath());
    20. File parent = outFile.getParentFile();
    21. if ((!parent.exists()) && (!parent.mkdirs())) {
    22. continue;
    23. }
    24. if (StringUtils.isNotBlank(passWord)) {
    25. result = item.extractSlow(data -> {
    26. try {
    27. IOUtils.write(data, new FileOutputStream(outFile, true));
    28. } catch (Exception e) {
    29. e.printStackTrace();
    30. }
    31. hash[0] ^= Arrays.hashCode(data); // Consume data
    32. sizeArray[0] += data.length;
    33. return data.length; // Return amount of consumed
    34. }, passWord);
    35. } else {
    36. result = item.extractSlow(data -> {
    37. try {
    38. IOUtils.write(data, new FileOutputStream(outFile, true));
    39. } catch (Exception e) {
    40. e.printStackTrace();
    41. }
    42. hash[0] ^= Arrays.hashCode(data); // Consume data
    43. sizeArray[0] += data.length;
    44. return data.length; // Return amount of consumed
    45. });
    46. }
    47. if (result == ExtractOperationResult.OK) {
    48. log.error("解压rar成功...." + String.format("%9X | %10s | %s", hash[0], sizeArray[0], item.getPath()));
    49. } else if (StringUtils.isNotBlank(passWord)) {
    50. log.error("解压rar成功:密码错误或者其他错误...." + result);
    51. return "password";
    52. } else {
    53. return "rar error";
    54. }
    55. }
    56. }
    57. } catch (Exception e) {
    58. log.error("unRar error", e);
    59. return e.getMessage();
    60. } finally {
    61. try {
    62. inArchive.close();
    63. randomAccessFile.close();
    64. } catch (Exception e) {
    65. e.printStackTrace();
    66. }
    67. }
    68. return "";
    69. }

    4、7z解压

    1. private static String un7z(String rootPath, String sourceRarPath, String destDirPath, String passWord) {
    2. try {
    3. File srcFile = new File(rootPath + sourceRarPath);//获取当前压缩文件
    4. // 判断源文件是否存在
    5. if (!srcFile.exists()) {
    6. throw new Exception(srcFile.getPath() + "所指文件不存在");
    7. }
    8. //开始解压
    9. SevenZFile zIn = null;
    10. if (StringUtils.isNotBlank(passWord)) {
    11. zIn = new SevenZFile(srcFile, passWord.toCharArray());
    12. } else {
    13. zIn = new SevenZFile(srcFile);
    14. }
    15. SevenZArchiveEntry entry = null;
    16. File file = null;
    17. while ((entry = zIn.getNextEntry()) != null) {
    18. if (!entry.isDirectory()) {
    19. file = new File(rootPath + destDirPath, entry.getName());
    20. if (!file.exists()) {
    21. new File(file.getParent()).mkdirs();//创建此文件的上级目录
    22. }
    23. OutputStream out = new FileOutputStream(file);
    24. BufferedOutputStream bos = new BufferedOutputStream(out);
    25. int len = -1;
    26. byte[] buf = new byte[1024];
    27. while ((len = zIn.read(buf)) != -1) {
    28. bos.write(buf, 0, len);
    29. }
    30. // 关流顺序,先打开的后关闭
    31. bos.close();
    32. out.close();
    33. }
    34. }
    35. } catch (Exception e) {
    36. log.error("un7z is error", e);
    37. return e.getMessage();
    38. }
    39. return "";
    40. }

    5、解压统一入口封装

    1. public static Map<String,Object> unFile(String rootPath, String sourcePath, String destDirPath, String passWord) {
    2. Map<String,Object> resultMap = new HashMap<String, Object>();
    3. String result = "";
    4. if (sourcePath.toLowerCase().endsWith(".zip")) {
    5. //Wrong password!
    6. result = unZip(rootPath, sourcePath, destDirPath, passWord);
    7. } else if (sourcePath.toLowerCase().endsWith(".rar")) {
    8. //java.security.InvalidAlgorithmParameterException: password should be specified
    9. result = unRar(rootPath, sourcePath, destDirPath, passWord);
    10. System.out.println(result);
    11. } else if (sourcePath.toLowerCase().endsWith(".7z")) {
    12. //PasswordRequiredException: Cannot read encrypted content from G:\ziptest\11111111.7z without a password
    13. result = un7z(rootPath, sourcePath, destDirPath, passWord);
    14. }
    15. resultMap.put("resultMsg", 1);
    16. if (StringUtils.isNotBlank(result)) {
    17. if (result.contains("password")) resultMap.put("resultMsg", 2);
    18. if (!result.contains("password")) resultMap.put("resultMsg", 3);
    19. }
    20. resultMap.put("files", null);
    21. //System.out.println(result + "==============");
    22. return resultMap;
    23. }

    6、测试代码

    1. Long start = System.currentTimeMillis();
    2. unFile("D:/rarfetch0628/","apache-tomcat-8.5.69.zip","apache-tomcat-zip","222");
    3. long end = System.currentTimeMillis();
    4. System.out.println("zip解压耗时==" + (end - start) + "毫秒");
    5. System.out.println("============================================================");
    6. Long rar4start = System.currentTimeMillis();
    7. unFile("D:/rarfetch0628/","apache-tomcat-8.5.69-4.rar","apache-tomcat-rar4","222");
    8. long rar4end = System.currentTimeMillis();
    9. System.out.println("rar4解压耗时==" + (rar4end - rar4start)+ "毫秒");
    10. System.out.println("============================================================");
    11. Long rar5start = System.currentTimeMillis();
    12. unFile("D:/rarfetch0628/","apache-tomcat-8.5.69-5.rar","apache-tomcat-rar5","222");
    13. long rar5end = System.currentTimeMillis();
    14. System.out.println("rar5解压耗时==" + (rar5end - rar5start)+ "毫秒");
    15. System.out.println("============================================================");
    16. Long zstart = System.currentTimeMillis();
    17. unFile("D:/rarfetch0628/","apache-tomcat-8.5.69.7z","apache-tomcat-7z","222");
    18. long zend = System.currentTimeMillis();
    19. System.out.println("7z解压耗时==" + (zend - zstart)+ "毫秒");
    20. System.out.println("============================================================");

    在控制台中可以看到以下结果:

    总结:本文采用java语言实现了对zip和rar、7z文件的解压统一算法。并对比了相应的解压速度,支持传入密码进行在线解压。本文参考了:https://blog.csdn.net/luanwuqingyang/article/details/121114113,不过博主的文章代码直接运行有问题,这里进行了调整,主要优化的点如下:

    1、pom.xml 遗漏了slf4j、commons-lang3、xdocreport等依赖

    2、zip路径优化

    3、去掉一些无用信息

    4、优化异常信息

  • 相关阅读:
    互联网摸鱼日报(2023-10-14)
    身份证号码算法解析与Java代码实现
    Hadoop 之文件读取
    Java计算字符串中指定字符的出现次数
    2.23每日一题(反常积分收敛性的判断)
    TypeError: namedtuple() got an unexpected keyword argument -verbose
    ES6 入门教程 18 Iterator 和 for...of 循环 18.7 for...of 循环
    睿趣科技:现在做抖音网店卖啥好
    更适合爬虫的正则表达式
    2022/8/2 考试总结
  • 原文地址:https://blog.csdn.net/yelangkingwuzuhu/article/details/125500248