JAVA调用外部工具(7-Zip)解压zip文件

本文详细介绍使用Java解压ZIP和RAR格式的压缩文件的方法,包括利用7-Zip和相关库进行解压的过程,以及如何处理不同操作系统下的路径转换。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、下载安装7-Zip

https://www.7-zip.org/

2、代码实现

 2、1maven依赖

<dependencies>
		<!-- https://mvnrepository.com/artifact/com.github.junrar/junrar -->
		<dependency>
			<groupId>com.github.junrar</groupId>
			<artifactId>junrar</artifactId>
			<version>0.7</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/commons-logging/commons-logging -->
		<dependency>
			<groupId>commons-logging</groupId>
			<artifactId>commons-logging</artifactId>
			<version>1.1.1</version>
		</dependency>
</dependencies>

2、2代码实现 

package com.jxx.demo001;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

import com.github.junrar.Archive;
import com.github.junrar.rarfile.FileHeader;

public class ZipUtil {

	/**
	 * 解压zip
	 *
	 * @param zipFile
	 * @param descDir
	 * @throws Exception
	 */
	public void unZipFiles(File zipFile, String descDir) throws Exception {
		System.out.println("******************解压开始********************");
		File pathFile = new File(descDir);
		if (!pathFile.exists()) {
			pathFile.mkdirs();
		}
		ZipFile zip = new ZipFile(zipFile, Charset.forName("GBK"));
		for (Enumeration entries = zip.entries(); entries.hasMoreElements();) {
			ZipEntry entry = (ZipEntry) entries.nextElement();
			String zipEntryName = entry.getName();
			InputStream in = zip.getInputStream(entry);
			String outPath = (descDir + "/" + zipEntryName).replaceAll("\\*", "/");
			// 判断路径是否存在,不存在则创建文件路径
			File file = new File(outPath.substring(0, outPath.lastIndexOf('/')));
			if (!file.exists()) {
				file.mkdirs();
			}
			// 判断文件全路径是否为文件夹,如果是上面已经上传,不需要解压
			if (new File(outPath).isDirectory()) {
				continue;
			}
			OutputStream out = new FileOutputStream(outPath);
			byte[] buf1 = new byte[1024];
			int len;
			while ((len = in.read(buf1)) > 0) {
				out.write(buf1, 0, len);
			}
			if ((zipEntryName.trim().lastIndexOf("/")) == -1) {

			}
			in.close();
			out.close();
		}
		System.out.println("******************解压完毕********************");
	}

	/**
	 * 解压rar格式压缩包。
	 * 依赖java-unrar-0.7.jar 和 commons-logging-1.1.1.jar
	 */
	public void unRarFiles(File rarFile, String descDir) throws Exception {
		Archive a = null;
		FileOutputStream fos = null;
		try {
			a = new Archive(rarFile);
			FileHeader fh = a.nextFileHeader();
			while (fh != null) {
				if (!fh.isDirectory()) {
					// 1 根据不同的操作系统拿到相应的 destDirName 和 destFileName
					// String compressFileName = fh.getFileNameString().trim();
					String compressFileName = fh.getFileNameW().trim();
					if (!existZH(compressFileName)) {
						compressFileName = fh.getFileNameString().trim();
					}
					String destFileName = "";
					String destDirName = "";
					// 非windows系统
					if (File.separator.equals("/")) {
						destFileName = descDir + compressFileName.replaceAll("\\\\", "/");
						destDirName = destFileName.substring(0, destFileName.lastIndexOf("/"));
						// windows系统
					} else {
						destFileName = descDir + compressFileName.replaceAll("/", "\\\\");
						destDirName = destFileName.substring(0, destFileName.lastIndexOf("\\"));
					}
					// 2创建文件夹
					File dir = new File(destDirName);
					if (!dir.exists() || !dir.isDirectory()) {
						dir.mkdirs();
					}
					// 3解压缩文件
					fos = new FileOutputStream(new File(destFileName));
					a.extractFile(fh, fos);
					fos.close();
					fos = null;
				}
				fh = a.nextFileHeader();
			}
			a.close();
			a = null;
		} catch (Exception e) {
			throw e;
		} finally {
			if (fos != null) {
				try {
					fos.close();
					fos = null;
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
			if (a != null) {
				try {
					a.close();
					a = null;
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
	}

	public static boolean existZH(String str) {
		String regEx = "[\\u4e00-\\u9fa5]";
		Pattern p = Pattern.compile(regEx);
		Matcher m = p.matcher(str);
		while (m.find()) {
			return true;
		}
		return false;
	}

	/**
	 * 文件夹遍历
	 * 
	 * @param path
	 * @throws Exception
	 */
	public void traverse(String path, String parent_id) throws Exception {
		System.out.println("path---->" + path);
		File file = new File(path);
		Map<String, Object> map = new HashMap<String, Object>();
		if (file.exists()) {
			File[] files = file.listFiles();
			if (files.length == 0) {
				System.out.println("文件夹是空的!");
				return;
			} else {
				String k_id = UUID.randomUUID().toString();

				for (File file2 : files) {
					if (file2.isDirectory()) {// 文件夹

						traverse(file2.getAbsolutePath(), parent_id);
						parent_id = k_id;
					} else if (file2.isFile()) {// 文件

					}
				}
			}
		} else {
			System.out.println("文件不存在!");
		}
	}

	/**
	 * 采用命令行方式解压文件
	 * 
	 * @param zipFile 压缩文件
	 * @param destDir 解压结果路径
	 * @param cmdPath 7z.exe的路径
	 * @return
     * 存在proc.waitFor()阻塞问题--》解决看cmd7zUnzipUpdate方法
	 */
	public static void cmd7zUnzip(File rarFile, String destDir) {
		// 解决路径中存在/..格式的路径问题
		destDir = new File(destDir).getAbsoluteFile().getAbsolutePath();
		while (destDir.contains("..")) {
			String[] sepList = destDir.split("\\\\");
			destDir = "";
			for (int i = 0; i < sepList.length; i++) {
				if (!"..".equals(sepList[i]) && i < sepList.length - 1 && "..".equals(sepList[i + 1])) {
					i++;
				} else {
					destDir += sepList[i] + File.separator;
				}
			}
		}
		String path = System.getProperty("user.dir");
		boolean bool = false;
		if (rarFile.exists()) {
			// 开始调用命令行解压,参数-o+是表示覆盖的意思
			String cmdPath = "E:/jiangxx/zip7z/7-Zip/7z.exe";
            // 所有空格都替换成带有双引号的空格
			cmdPath = cmdPath.replaceAll(" ", "\" \"");
			String cmd = cmdPath + " x " + rarFile.getPath() + " -o" + destDir;
			System.out.println(cmd);
			try {
				Process proc = Runtime.getRuntime().exec(cmd);
				if (proc.waitFor() != 0) {
					if (proc.exitValue() == 0) {
						bool = false;
					}
				} else {
					bool = true;
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
			System.out.println("解压" + (bool ? "成功" : "失败"));
		}
	}

    /**
	 * 采用命令行方式解压文件
	 * 
	 * @param zipFile 压缩文件
	 * @param destDir 解压结果路径
	 * @param cmdPath 7z.exe的路径
	 * @return
     * update:20200805--解决proc.waitFor()阻塞问题
	 */
	public static void cmd7zUnzipUpdate(File rarFile, String destDir) {
		// 解决路径中存在/..格式的路径问题
		destDir = new File(destDir).getAbsoluteFile().getAbsolutePath();
		while (destDir.contains("..")) {
			String[] sepList = destDir.split("\\\\");
			destDir = "";
			for (int i = 0; i < sepList.length; i++) {
				if (!"..".equals(sepList[i]) && i < sepList.length - 1 && "..".equals(sepList[i + 1])) {
					i++;
				} else {
					destDir += sepList[i] + File.separator;
				}
			}
		}
		String path = System.getProperty("user.dir");
		boolean bool = false;
		if (rarFile.exists()) {
			// 开始调用命令行解压,参数-o+是表示覆盖的意思
			String cmdPath = "E:/jiangxx/zip7z/7-Zip/7z.exe";
            // 所有空格都替换成带有双引号的空格
			cmdPath = cmdPath.replaceAll(" ", "\" \"");
			String cmd = cmdPath + " x " + rarFile.getPath() + " -o" + destDir;
			System.out.println(cmd);
            //"-o" +destDir =>注意"-o"不能加空格
            String[] cmdArr = {cmdPath,"x",rarFile.getPath(),"-o" +destDir};
			try {
				//Process proc = Runtime.getRuntime().exec(cmd);
                //注意:
            	//1、proc.waitFor()可能会造成阻塞,故用new ProcessBuilder(cmd).redirectErrorStream(true).start();
            	//2、new ProcessBuilder(cmdArr),命令不能包含空格,传入数组
                Process proc = new ProcessBuilder(cmdArr).redirectErrorStream(true).start();
                try {
    				if (proc.waitFor() != 0) {
    				    if (proc.exitValue() == 0) {
    				        bool = false;
    				    }
    				} else {
    				    bool = true;
    				}
    			} catch (InterruptedException e) {
    				// TODO Auto-generated catch block
    				e.printStackTrace();
    			} finally {  
    				proc.getErrorStream().close();  
    				proc.getInputStream().close();  
    				proc.getOutputStream().close();  
                }

			} catch (Exception e) {
				e.printStackTrace();
			}
			System.out.println("解压" + (bool ? "成功" : "失败"));
		}
	}

    //测试
	public static void main(String[] args) {
		cmd7zUnzip(new File("E:/testwinrar/测试.zip"), "E:/testwinrar/666");
	}
}

补充说明内容:

使用jdk自带的运行时变量 RunTime.getRunTime() 去执行bash命令。因为该bash操作耗时比较长,所以使用了Process.waitFor()去等待子线程运行结束。

这个时候发现程序卡在waitFor()没有继续往下执行。

官方解释:

/**
     * Causes the current thread to wait, if necessary, until the
     * process represented by this {@code Process} object has
     * terminated.  This method returns immediately if the subprocess
     * has already terminated.  If the subprocess has not yet
     * terminated, the calling thread will be blocked until the
     * subprocess exits.
     *
     * @return the exit value of the subprocess represented by this
     *         {@code Process} object.  By convention, the value
     *         {@code 0} indicates normal termination.
     * @throws InterruptedException if the current thread is
     *         {@linkplain Thread#interrupt() interrupted} by another
     *         thread while it is waiting, then the wait is ended and
     *         an {@link InterruptedException} is thrown.
     */
    abstract public int waitFor() throws InterruptedException;

waitFor:等待子进程执行结束,或者已终止子进程,此方法立即返回。
当RunTime对象调用exec方法后,jvm会创建一个子进程,该子进程与jvm建立三个管道连接:标准输入流、标准输出流、标准错误流。假设该子进程不断向标准输入流、标准输出流写数据,而jvm不读取的话,会导致缓冲区塞满而无法继续写数据,最终堵塞在waitFor这里。

java.lang.ProcessBuilder.redirectErrorStream() 方法告诉此进程生成器是否合并标准错误和标准输出。如果此属性为true,则通过子进程所产生的任何错误输出随后由该对象的start()方法启动将与标准输出合并,这样既可以用Process.getInputStream()方法来读取。此使得更容易与对应的输出相关的错误消息。初始值是false。
 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值