废话不多说直接上代码
1.相关依赖pom
<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>
2.解压压缩文件工具类
import net.sf.sevenzipjbinding.IInArchive; import net.sf.sevenzipjbinding.SevenZip; import net.sf.sevenzipjbinding.impl.RandomAccessFileInStream; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.*; import java.nio.charset.Charset; import java.util.Enumeration; import java.util.HashMap; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import java.util.zip.ZipOutputStream; public class UnZipAndRarUtil { private static Logger logger = LoggerFactory.getLogger(UnZipAndRarUtil.class); private static final int BUFFER_SIZE = 2 * 1024; /** * 压缩成ZIP 方法1 * * @param srcDir 压缩文件夹路径 * @param out 压缩文件输出流 * @param KeepDirStructure 是否保留原来的目录结构,true:保留目录结构; * false:所有文件跑到压缩包根目录下(注意:不保留目录结构可能会出现同名文件,会压缩失败) * @throws RuntimeException 压缩失败会抛出运行时异常 */ public static void toZip(String srcDir, OutputStream out, boolean KeepDirStructure) { long start = System.currentTimeMillis(); ZipOutputStream zos = null; try { zos = new ZipOutputStream(out); File sourceFile = new File(srcDir); compress(sourceFile, zos, sourceFile.getName(), KeepDirStructure); long end = System.currentTimeMillis(); logger.debug("压缩完成,耗时:" + (end - start) + " ms"); } catch (Exception e) { throw new RuntimeException("zip error from ZipUtils", e); } finally { if (zos != null) { try { zos.close(); } catch (IOException e) { e.printStackTrace(); } } } } /** * 压缩成ZIP 方法2 * * @param srcFiles 需要压缩的文件列表 * @param out 压缩文件输出流 * @throws RuntimeException 压缩失败会抛出运行时异常 */ public static void toZip(List<File> srcFiles, OutputStream out) { long start = System.currentTimeMillis(); HashMap<Object, Object> index = new HashMap<>(); int count = 0; ZipOutputStream zos = null; try { zos = new ZipOutputStream(out); for (File srcFile : srcFiles) { String fileName = srcFile.getName(); logger.debug("压缩文件名称信息:{}", fileName); byte[] buf = new byte[BUFFER_SIZE]; //解决文件重名导致压缩失败问题 if (index.containsKey(fileName)) { count++; zos.putNextEntry(new ZipEntry("(" + count + ")" + "-" + srcFile.getName())); index.put("(" + count + ")" + "-" + srcFile.getName(), true); } else { zos.putNextEntry(new ZipEntry(srcFile.getName())); index.put(srcFile.getName(), true); } int len; FileInputStream in = new FileInputStream(srcFile); while ((len = in.read(buf)) != -1) { zos.write(buf, 0, len); } zos.closeEntry(); in.close(); srcFile.delete(); } long end = System.currentTimeMillis(); logger.info("压缩完成,耗时:" + (end - start) + " ms"); } catch (Exception e) { throw new RuntimeException("zip error from ZipUtils", e); } finally { if (zos != null) { try { zos.close(); } catch (IOException e) { e.printStackTrace(); } } } } /** * 递归压缩方法 * * @param sourceFile 源文件 * @param zos zip输出流 * @param name 压缩后的名称 * @param KeepDirStructure 是否保留原来的目录结构,true:保留目录结构; * false:所有文件跑到压缩包根目录下(注意:不保留目录结构可能会出现同名文件,会压缩失败) * @throws Exception */ private static void compress(File sourceFile, ZipOutputStream zos, String name, boolean KeepDirStructure) { try { byte[] buf = new byte[BUFFER_SIZE]; if (sourceFile.isFile()) { // 向zip输出流中添加一个zip实体,构造器中name为zip实体的文件的名字 zos.putNextEntry(new ZipEntry(name)); // copy文件到zip输出流中 int len; FileInputStream in = new FileInputStream(sourceFile); while ((len = in.read(buf)) != -1) { zos.write(buf, 0, len); } zos.closeEntry(); in.close(); } else { File[] listFiles = sourceFile.listFiles(); if (listFiles == null || listFiles.length == 0) { // 需要保留原来的文件结构时,需要对空文件夹进行处理 if (KeepDirStructure) { // 空文件夹的处理 zos.putNextEntry(new ZipEntry(name + "/")); // 没有文件,不需要文件的copy zos.closeEntry(); } } else { for (File file : listFiles) { // 判断是否需要保留原来的文件结构 if (KeepDirStructure) { // 注意:file.getName()前面需要带上父文件夹的名字加一斜杠, // 不然最后压缩包中就不能保留原来的文件结构,即:所有文件都跑到压缩包根目录下了 compress(file, zos, name + "/" + file.getName(), KeepDirStructure); } else { compress(file, zos, file.getName(), KeepDirStructure); } } } } } catch (IOException e) { e.printStackTrace(); } } /** * <功能描述:> 解压文件到指定目录 * * @param zipFile zip文件 * @param descDir 目标目录 * @param levelDepth 解压的最大层级 * @return void */ @SuppressWarnings("rawtypes") public static int unPackZip(File zipFile, String descDir, int levelDepth) { int unzipFileNum = 0; try { if (!descDir.endsWith("/")) { descDir = descDir + "/"; } File pathFile = new File(descDir); if (!pathFile.exists()) { pathFile.mkdirs(); } // 解决zip文件中有中文目录或者中文文件 ZipFile zip = new ZipFile(zipFile, Charset.forName("GBK")); for (Enumeration entries = zip.entries(); entries.hasMoreElements(); ) { ZipEntry entry = (ZipEntry) entries.nextElement(); String zipEntryName = entry.getName(); OutputStream out = null; try (InputStream in = zip.getInputStream(entry)) { // 文件名特殊处理 String fileEnd = ""; if (zipEntryName.contains("/")) { fileEnd = entry.getName().substring(entry.getName().lastIndexOf('/') + 1); } else { fileEnd = entry.getName(); } zipEntryName = zipEntryName.substring(0, zipEntryName.lastIndexOf('/') + 1) + fileEnd; 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; } // 获取当前层级 int currentLevel = getCurrentLevel(descDir, outPath); if (currentLevel <= levelDepth) { ++unzipFileNum; out = new FileOutputStream(outPath); byte[] buf1 = new byte[1024]; int len; while ((len = in.read(buf1)) > 0) { out.write(buf1, 0, len); } //输出文件路径信息 logger.info(String.format("解压ZIP文件= [%s] 中的文件路径[%s]!", zipFile.getName(), outPath)); } } catch (Exception e) { logger.error(String.format("解压ZIP文件= [%s] 中的文件出错!", zipFile.getName()), e); } finally { if (null != out) { out.close(); } } } zip.close(); logger.info(String.format("解压[%s]文件,共解压出文件=[%s]个文件!", zipFile.getName(), unzipFileNum)); } catch (IOException e) { logger.error("解压异常:{}", e); } return unzipFileNum; } private static int getCurrentLevel(String descDir, String outPath) { int currentLevel = 0; String innnerPath = outPath.substring(descDir.length()); String[] folderArray = innnerPath.split("/"); if (null != folderArray && folderArray.length > 1) { currentLevel = folderArray.length - 1; } return currentLevel; } public static int unRarFiles(File rarFile, String descDir) { if (!descDir.endsWith("/")) { descDir = descDir + "/"; } File pathFile = new File(descDir); if (!pathFile.exists()) { pathFile.mkdirs(); } try { // 第一个参数是需要解压的压缩包路径,第二个参数参考JdkAPI文档的RandomAccessFile //r代表以只读的方式打开文本,也就意味着不能用write来操作文件 RandomAccessFile randomAccessFile = new RandomAccessFile(rarFile.toString(), "r"); // null - autodetect IInArchive archive = SevenZip.openInArchive(null, new RandomAccessFileInStream(randomAccessFile)); int[] in = new int[archive.getNumberOfItems()]; for (int i = 0; i < in.length; i++) { in[i] = i; } AtomicInteger fileSum = new AtomicInteger(0); archive.extract(in, false, new ExtractCallback(archive, pathFile.getAbsolutePath() + "/")); archive.close(); randomAccessFile.close(); return fileSum.get(); } catch (Exception e) { logger.error("解压rar出错 {}", e.getMessage()); } return 0; } // public static void main(String[] args) throws Exception { // String zipFilepath = "D:\\工作内容.zip"; // unPackZip(new File(zipFilepath), null, "D:\\data\\fy\\"); // } }
3.创建提取文件实现类(IInArchive类属于SevenZip.Archive包)
import net.sf.sevenzipjbinding.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.*; public class ExtractCallback implements IArchiveExtractCallback { private static Logger log = LoggerFactory.getLogger(ExtractCallback.class); private int index; private IInArchive inArchive; private String ourDir; public ExtractCallback(IInArchive inArchive, String ourDir) { this.inArchive = inArchive; this.ourDir = ourDir; } @Override public void setCompleted(long arg0) throws SevenZipException { } @Override public void setTotal(long arg0) throws SevenZipException { } @Override public ISequentialOutStream getStream(int index, ExtractAskMode extractAskMode) throws SevenZipException { this.index = index; String path = (String) inArchive.getProperty(index, PropID.PATH); final boolean isFolder = (boolean) inArchive.getProperty(index, PropID.IS_FOLDER); String finalPath = path; File newfile = null; try { String fileEnd = ""; //对文件名,文件夹特殊处理 if (finalPath.contains(File.separator)) { fileEnd = finalPath.substring(finalPath.lastIndexOf(File.separator) + 1); } else { fileEnd = finalPath; } finalPath = finalPath.substring(0, finalPath.lastIndexOf(File.separator) + 1) + fileEnd; //目录层级 finalPath = finalPath.replaceAll("\\\\", "/"); String suffixName = ""; int suffixIndex = fileEnd.lastIndexOf("."); if (suffixIndex != -1) { suffixName = fileEnd.substring(suffixIndex + 1); } newfile = createFile(isFolder, ourDir + finalPath); final boolean directory = (boolean) inArchive.getProperty(index, PropID.IS_FOLDER); } catch (Exception e) { log.error("rar解压失败{}", e.getMessage()); } File finalFile = newfile; return data -> { save2File(finalFile, data); return data.length; }; } @Override public void prepareOperation(ExtractAskMode arg0) throws SevenZipException { } @Override public void setOperationResult(ExtractOperationResult extractOperationResult) throws SevenZipException { } public static File createFile(boolean isFolder, String path) { //前置是因为空文件时不会创建文件和文件夹 File file = new File(path); try { if (!isFolder) { File parent = file.getParentFile(); if ((!parent.exists())) { parent.mkdirs(); } if (!file.exists()) { file.createNewFile(); } } else { if ((!file.exists())) { file.mkdirs(); } } } catch (Exception e) { log.error("rar创建文件或文件夹失败 {}", e.getMessage()); } return file; } public static boolean save2File(File file, byte[] msg) { OutputStream fos = null; try { fos = new FileOutputStream(file, true); fos.write(msg); fos.flush(); return true; } catch (FileNotFoundException e) { log.error("rar保存文件失败{}", e.getMessage()); return false; } catch (IOException e) { log.error("rar保存文件失败{}", e.getMessage()); return false; } finally { try { fos.close(); } catch (IOException e) { log.error("rar保存文件失败{}", e.getMessage()); } } }