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

简介: 本文采用java语言实现了对zip和rar、7z文件的解压统一算法。并对比了相应的解压速度,支持传入密码进行在线解压。

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

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

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

image.png

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

image.png

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

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

1、pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

<modelVersion>4.0.0</modelVersion>

<groupId>com.yelang</groupId>

<artifactId>7zdemo</artifactId>

<version>0.0.1-SNAPSHOT</version>

<dependencies>

 <dependency>

  <groupId>net.lingala.zip4j</groupId>

  <artifactId>zip4j</artifactId>

  <version>2.9.0</version>

 </dependency>

 <dependency>

  <groupId>net.sf.sevenzipjbinding</groupId>

  <artifactId>sevenzipjbinding</artifactId>

  <version>16.02-2.01</version>

 </dependency>

 <dependency>

  <groupId>net.sf.sevenzipjbinding</groupId>

  <artifactId>sevenzipjbinding-all-platforms</artifactId>

  <version>16.02-2.01</version>

 </dependency>

 <dependency>

  <groupId>org.tukaani</groupId>

  <artifactId>xz</artifactId>

  <version>1.9</version>

 </dependency>

 <dependency>

  <groupId>org.apache.commons</groupId>

  <artifactId>commons-compress</artifactId>

  <version>1.21</version>

 </dependency>

 

 <!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->

 <dependency>

     <groupId>org.slf4j</groupId>

     <artifactId>slf4j-api</artifactId>

     <version>1.7.30</version>

 </dependency>

 

 <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->

 <dependency>

     <groupId>org.apache.commons</groupId>

     <artifactId>commons-lang3</artifactId>

     <version>3.12.0</version>

 </dependency>

 

 <!-- https://mvnrepository.com/artifact/fr.opensagres.xdocreport/xdocreport -->

 <dependency>

     <groupId>fr.opensagres.xdocreport</groupId>

     <artifactId>xdocreport</artifactId>

     <version>1.0.6</version>

 </dependency>

 

</dependencies>

</project>

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

2、zip解压


@SuppressWarnings("resource")

private static String unZip(String rootPath, String sourceRarPath, String destDirPath, String passWord) {

       ZipFile zipFile = null;

       String result = "";

       try {

        //String filePath = sourceRarPath;

        String filePath = rootPath + sourceRarPath;

           if (StringUtils.isNotBlank(passWord)) {

               zipFile = new ZipFile(filePath, passWord.toCharArray());

           } else {

               zipFile = new ZipFile(filePath);

           }

           zipFile.setCharset(Charset.forName("GBK"));

           zipFile.extractAll(rootPath + destDirPath);

       } catch (Exception e) {

           log.error("unZip error", e);

           return e.getMessage();

       }

       return result;

   }


3、rar解压


private static String unRar(String rootPath, String sourceRarPath, String destDirPath, String passWord) {

       String rarDir = rootPath + sourceRarPath;

       String outDir = rootPath + destDirPath + File.separator;

       RandomAccessFile randomAccessFile = null;

       IInArchive inArchive = null;

       try {

           // 第一个参数是需要解压的压缩包路径,第二个参数参考JdkAPI文档的RandomAccessFile

           randomAccessFile = new RandomAccessFile(rarDir, "r");

           if (StringUtils.isNotBlank(passWord))

               inArchive = SevenZip.openInArchive(null, new RandomAccessFileInStream(randomAccessFile), passWord);

           else

               inArchive = SevenZip.openInArchive(null, new RandomAccessFileInStream(randomAccessFile));

           ISimpleInArchive simpleInArchive = inArchive.getSimpleInterface();

           for (final ISimpleInArchiveItem item : simpleInArchive.getArchiveItems()) {

               final int[] hash = new int[]{0};

               if (!item.isFolder()) {

                   ExtractOperationResult result;

                   final long[] sizeArray = new long[1];

                   File outFile = new File(outDir + item.getPath());

                   File parent = outFile.getParentFile();

                   if ((!parent.exists()) && (!parent.mkdirs())) {

                       continue;

                   }

                   if (StringUtils.isNotBlank(passWord)) {

                       result = item.extractSlow(data -> {

                           try {

                               IOUtils.write(data, new FileOutputStream(outFile, true));

                           } catch (Exception e) {

                               e.printStackTrace();

                           }

                           hash[0] ^= Arrays.hashCode(data); // Consume data

                           sizeArray[0] += data.length;

                           return data.length; // Return amount of consumed

                       }, passWord);

                   } else {

                       result = item.extractSlow(data -> {

                           try {

                               IOUtils.write(data, new FileOutputStream(outFile, true));

                           } catch (Exception e) {

                               e.printStackTrace();

                           }

                           hash[0] ^= Arrays.hashCode(data); // Consume data

                           sizeArray[0] += data.length;

                           return data.length; // Return amount of consumed

                       });

                   }

                 

                   if (result == ExtractOperationResult.OK) {

                       log.error("解压rar成功...." + String.format("%9X | %10s | %s", hash[0], sizeArray[0], item.getPath()));

                   } else if (StringUtils.isNotBlank(passWord)) {

                       log.error("解压rar成功:密码错误或者其他错误...." + result);

                       return "password";

                   } else {

                       return "rar error";

                   }

               }

           }

       } catch (Exception e) {

           log.error("unRar error", e);

           return e.getMessage();

       } finally {

           try {

               inArchive.close();

               randomAccessFile.close();

           } catch (Exception e) {

               e.printStackTrace();

           }

       }

       return "";

   }


4、7z解压


private static String un7z(String rootPath, String sourceRarPath, String destDirPath, String passWord) {

       try {

           File srcFile = new File(rootPath + sourceRarPath);//获取当前压缩文件

           // 判断源文件是否存在

           if (!srcFile.exists()) {

               throw new Exception(srcFile.getPath() + "所指文件不存在");

           }

           //开始解压

           SevenZFile zIn = null;

           if (StringUtils.isNotBlank(passWord)) {

            zIn = new SevenZFile(srcFile, passWord.toCharArray());

           }  else {

            zIn = new SevenZFile(srcFile);

           }

           SevenZArchiveEntry entry = null;

           File file = null;

           while ((entry = zIn.getNextEntry()) != null) {

               if (!entry.isDirectory()) {

                   file = new File(rootPath + destDirPath, entry.getName());

                   if (!file.exists()) {

                       new File(file.getParent()).mkdirs();//创建此文件的上级目录

                   }

                   OutputStream out = new FileOutputStream(file);

                   BufferedOutputStream bos = new BufferedOutputStream(out);

                   int len = -1;

                   byte[] buf = new byte[1024];

                   while ((len = zIn.read(buf)) != -1) {

                       bos.write(buf, 0, len);

                   }

                   // 关流顺序,先打开的后关闭

                   bos.close();

                   out.close();

               }

           }

       } catch (Exception e) {

           log.error("un7z is error", e);

           return e.getMessage();

       }

       return "";

   }


5、解压统一入口封装


public static Map<String,Object> unFile(String rootPath, String sourcePath, String destDirPath, String passWord) {

    Map<String,Object> resultMap = new HashMap<String, Object>();

    String result = "";

       if (sourcePath.toLowerCase().endsWith(".zip")) {

           //Wrong password!

           result = unZip(rootPath, sourcePath, destDirPath, passWord);

       } else if (sourcePath.toLowerCase().endsWith(".rar")) {

           //java.security.InvalidAlgorithmParameterException: password should be specified

           result = unRar(rootPath, sourcePath, destDirPath, passWord);

           System.out.println(result);

       } else if (sourcePath.toLowerCase().endsWith(".7z")) {

           //PasswordRequiredException: Cannot read encrypted content from G:\ziptest\11111111.7z without a password

           result = un7z(rootPath, sourcePath, destDirPath, passWord);

       }

 

       resultMap.put("resultMsg", 1);

       if (StringUtils.isNotBlank(result)) {

           if (result.contains("password")) resultMap.put("resultMsg", 2);

           if (!result.contains("password")) resultMap.put("resultMsg", 3);

       }

       resultMap.put("files", null);

       //System.out.println(result + "==============");

       return resultMap;

   }


6、测试代码


Long start = System.currentTimeMillis();

unFile("D:/rarfetch0628/","apache-tomcat-8.5.69.zip","apache-tomcat-zip","222");

long end = System.currentTimeMillis();

System.out.println("zip解压耗时==" + (end - start) + "毫秒");

System.out.println("============================================================");

 

Long rar4start = System.currentTimeMillis();

unFile("D:/rarfetch0628/","apache-tomcat-8.5.69-4.rar","apache-tomcat-rar4","222");

long rar4end = System.currentTimeMillis();

System.out.println("rar4解压耗时==" + (rar4end - rar4start)+ "毫秒");

System.out.println("============================================================");

 

Long rar5start = System.currentTimeMillis();

unFile("D:/rarfetch0628/","apache-tomcat-8.5.69-5.rar","apache-tomcat-rar5","222");

long rar5end = System.currentTimeMillis();

System.out.println("rar5解压耗时==" + (rar5end - rar5start)+ "毫秒");

System.out.println("============================================================");

 

Long zstart = System.currentTimeMillis();

unFile("D:/rarfetch0628/","apache-tomcat-8.5.69.7z","apache-tomcat-7z","222");

long zend = System.currentTimeMillis();

System.out.println("7z解压耗时==" + (zend - zstart)+ "毫秒");

System.out.println("============================================================");


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

image.png

image.png

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

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

2、zip路径优化

3、去掉一些无用信息

4、优化异常信息

目录
相关文章
|
1月前
|
Java Unix Go
【Java】(8)Stream流、文件File相关操作,IO的含义与运用
Java 为 I/O 提供了强大的而灵活的支持,使其更广泛地应用到文件传输和网络编程中。!但本节讲述最基本的和流与 I/O 相关的功能。我们将通过一个个例子来学习这些功能。
162 1
|
2月前
|
存储 Java 关系型数据库
Java 项目实战基于面向对象思想的汽车租赁系统开发实例 汽车租赁系统 Java 面向对象项目实战
本文介绍基于Java面向对象编程的汽车租赁系统技术方案与应用实例,涵盖系统功能需求分析、类设计、数据库设计及具体代码实现,帮助开发者掌握Java在实际项目中的应用。
115 0
|
4月前
|
存储 Java 编译器
深入理解Java虚拟机--类文件结构
本内容介绍了Java虚拟机与Class文件的关系及其内部结构。Class文件是一种与语言无关的二进制格式,包含JVM指令集、符号表等信息。无论使用何种语言,只要能生成符合规范的Class文件,即可在JVM上运行。文章详细解析了Class文件的组成,包括魔数、版本号、常量池、访问标志、类索引、字段表、方法表和属性表等,并说明其在Java编译与运行过程中的作用。
135 0
|
4月前
|
安全 Java 测试技术
Java 大学期末实操项目在线图书管理系统开发实例及关键技术解析实操项目
本项目基于Spring Boot 3.0与Java 17,实现在线图书管理系统,涵盖CRUD操作、RESTful API、安全认证及单元测试,助力学生掌握现代Java开发核心技能。
224 0
|
4月前
|
存储 人工智能 Java
java之通过Http下载文件
本文介绍了使用Java实现通过文件链接下载文件到本地的方法,主要涉及URL、HttpURLConnection及输入输出流的操作。
306 0
|
4月前
|
监控 Java API
Java语言按文件创建日期排序及获取最新文件的技术
这段代码实现了文件创建时间的读取、文件列表的获取与排序以及获取最新文件的需求。它具备良好的效率和可读性,对于绝大多数处理文件属性相关的需求来说足够健壮。在实际应用中,根据具体情况,可能还需要进一步处理如访问权限不足、文件系统不支持某些属性等边界情况。
253 14
|
5月前
|
存储 算法 Java
【Java实例-智慧牌局】Java实现赌桌上的21点
游戏规则:游戏开始时,玩家和庄家各获得两张牌,玩家可以看到自己手中的两张牌以及庄家的一张明牌。玩家需要根据手中的牌面总和,选择“要牌”(Hit)以获取更多牌,或“停牌”(Stand)停止要牌。如果玩家的牌面总和超过21点,即为爆牌,玩家立即输掉游戏。若玩家选择停牌,庄家则开始行动,其策略是当牌面总和小于17点时必须继续要牌。若庄家牌面总和超过21点,则庄家爆牌,玩家获胜。若双方均未爆牌,最终比较牌面总和,更接近21点的一方获胜;若牌面总和相同,则游戏以平局结束。
87 0
|
5月前
|
Java 开发者
【Java实例-英雄对战】Java战斗之旅,既分胜负也决生死
游戏规则:在“英雄对战”中,玩家和敌人轮流选择行动,目标是在对方生命值归零前将其击败。游戏开始时,玩家和敌人都有100生命值。每回合,玩家可以选择“攻击”,“追击”,“闪避反击”这三种行动之一。
75 0
|
Java
JAVA读取文件的几种方法
喜欢的朋友可以关注下,粉丝也缺。 InputStreamReader+BufferedReader读取字符串 InputStreamReader 将字节流转换为字符流。
1378 0
[Java]读取文件方法大全
1、按字节读取文件内容2、按字符读取文件内容3、按行读取文件内容 4、随机读取文件内容 public class ReadFromFile {    /**     * 以字节为单位读取文件,常用于读二进制文件,如图片、声音、影像等文件。
796 0
下一篇
oss云网关配置