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
<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對zip,rar,7z文件帶密碼解壓實例詳解的詳細內容,更多關於Java文件帶密碼解壓的資料請關註WalkonNet其它相關文章!
推薦閱讀:
- Java輕松使用工具類實現獲取wav時間長度
- Java如何實現壓縮文件與解壓縮zip文件
- Java如何實現文件壓縮與上傳FTP
- Java根據ip地址獲取歸屬地實例詳解
- 在SSM框架中將圖片上傳到數據庫中的實現代碼