JAVA之ZIP、RAR解压工具类

JAVA之ZIP、RAR解压工具类,第1张

废话不多说直接上代码

1.相关依赖pom


    net.sf.sevenzipjbinding
    sevenzipjbinding
    16.02-2.01


    net.sf.sevenzipjbinding
    sevenzipjbinding-all-platforms
    16.02-2.01

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 srcFiles, OutputStream out) {
        long start = System.currentTimeMillis();
        HashMap 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());
            }
        }
    }

欢迎分享,转载请注明来源:内存溢出

原文地址: https://www.outofmemory.cn/langs/719999.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-25
下一篇 2022-04-25

发表评论

登录后才能评论

评论列表(0条)

保存