您现在的位置是:群英 > 开发技术 > 编程语言
Java对压缩文件破密解压的实现是怎样
Admin发表于 2022-10-09 18:12:06654 次浏览
这篇文章给大家分享的是“Java对压缩文件破密解压的实现是怎样”,文中的讲解内容简单清晰,易于理解,而且实用性强吗,对大家认识和了解“Java对压缩文件破密解压的实现是怎样”有一定的帮助,有需要的朋友可以参考了解看看,那么接下来就跟随小编的思路来往下学习吧
前言

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

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

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

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

从以上图表可以看到,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("============================================================");

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

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

本文参考代码在补充内容里,不过代码直接运行有问题,这里进行了调整,主要优化的点如下:

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

2、zip路径优化

3、去掉一些无用信息

4、优化异常信息

补充

1.maven引用

<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>

2.实现代码如下

import fr.opensagres.xdocreport.core.io.IOUtils;
import net.lingala.zip4j.ZipFile;
import net.sf.sevenzipjbinding.*;
import net.sf.sevenzipjbinding.impl.RandomAccessFileInStream;
import net.sf.sevenzipjbinding.simple.ISimpleInArchive;
import net.sf.sevenzipjbinding.simple.ISimpleInArchiveItem;
import org.apache.commons.compress.archivers.sevenz.SevenZArchiveEntry;
import org.apache.commons.compress.archivers.sevenz.SevenZFile;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.util.*;
 
 
public class ZipAndRarTools {
    private static final Logger log = LoggerFactory.getLogger(ZipAndRarTools.class);
 
    /*
    解压zip
    */
    private static String unZip(String rootPath, String sourceRarPath, String destDirPath, String passWord) {
        ZipFile zipFile = null;
 
        try {
 
            if (StringUtils.isNotBlank(passWord)) {
                zipFile = new ZipFile(filePath, passWord.toCharArray());
            } else {
                zipFile = new ZipFile(filePath);
            }
            zipFile.extractAll(rootPath + destDirPath);
        } catch (Exception e) {
            log.error("unZip error", e);
            return e.getMessage();
        }
        return "";
    }
 
 
    /*
       解压rar rar5
       */
    private static String unRar(String rootPath, String sourceRarPath, String destDirPath, String passWord) {
         /*final File rar = new File(rootPath + sourceRarPath);
       final File destinationFolder = new File(rootPath + destDirPath);
        destinationFolder.mkdir();
        try {
            Junrar.extract(rar, destinationFolder);
        } catch (Exception e) {
            log.error("unRar error", e);
            return e.getMessage();
        }*/
 
        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 "";
    }
 
 
    /*
     * 解压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))
                new SevenZFile(srcFile, passWord.getBytes());
            else
                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 "";
    }
 
    public static void unFile(String rootPath, String sourcePath, String destDirPath, String passWord) {
        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);
        } 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", data);
//        System.out.println(result + "==============");
        return resultMap;
    }
 
 
    public static void main(String[] args) {
        getFileList("G:\\ziptest\\", "测试.zip", "test3333", "密码");
    }
 
}



通过以上内容的阐述,相信大家对“Java对压缩文件破密解压的实现是怎样”已经有了进一步的了解,更多相关的问题,欢迎关注群英网络或到群英官网咨询客服。

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:mmqy2019@163.com进行举报,并提供相关证据,查实之后,将立刻删除涉嫌侵权内容。

标签: Java文件解压
相关信息推荐
2022-08-24 17:59:05 
摘要:本篇文章给大家带来了关于JavaScript的相关知识,其中主要介绍了关于网络请求与远程资源的相关问题,包括了跨源资源共享、预检请求、Fetch API等等内容,下面一起来看一下,希望对大家有帮助。
2022-08-10 17:49:08 
摘要:查询方法:1、使用array_search(),可搜索给定元素值并返回键名或索引,语法“array_search(元素值,数组)”;2、使用implode()和strpos(),语法“strpos(implode(数组),元素值."")”。
2022-02-11 17:50:20 
摘要:这篇文章给大家分享的是Python怎样给文件重命名的思路和方法。小编觉得挺实用的,因此分享给大家做个参考,文中的示例代码介绍得很详细,有需要的朋友可以参考,接下来就跟随小编一起了解看看吧。
云活动
推荐内容
热门关键词
热门信息
群英网络助力开启安全的云计算之旅
立即注册,领取新人大礼包
  • 联系我们
  • 24小时售后:4006784567
  • 24小时TEL :0668-2555666
  • 售前咨询TEL:400-678-4567

  • 官方微信

    官方微信
Copyright  ©  QY  Network  Company  Ltd. All  Rights  Reserved. 2003-2019  群英网络  版权所有   茂名市群英网络有限公司
增值电信经营许可证 : B1.B2-20140078   粤ICP备09006778号
免费拨打  400-678-4567
免费拨打  400-678-4567 免费拨打 400-678-4567 或 0668-2555555
微信公众号
返回顶部
返回顶部 返回顶部