业务背景:需要将zip包或者rar包进行解压缩,需要兼容rar4和rar5两种版本

maven 依赖包:

<dependency>
    <groupId>com.github.junrar</groupId>
    <artifactId>junrar</artifactId>
    <version>3.0.0</version>
</dependency>
<!--      解压rar5,所需依赖开始-->
<dependency>
    <groupId>com.github.axet</groupId>
    <artifactId>java-unrar</artifactId>
    <version>1.7.0-8</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>
<!--      解压rar5,所需依赖结束-->
String fileSuffix = FileUtil.judgeFileSuffix(fileInfo.getFileName());
try {
    if ("zip".equals(fileSuffix)) {
        FileUtil.unzip(fileFullPath, fileInfo.getLocationAddr()+File.separator);
    } else if ("rar".equals(fileSuffix)) {
        FileUtil.unRar(fileFullPath, fileInfo.getLocationAddr()+File.separator);
    }
}catch(Exception e){
    e.printStackTrace();
    File zipFile = new File(fileFullPath);
    FileSystemUtils.deleteRecursively(zipFile);
    log.error("服务器文件解析异常:{}...",fileInfo.getFileName());
    throw new BusinessException("rar文件:{}解析异常",fileInfo.getFileName());
}

File工具类封装解压缩方法

import com.github.junrar.Archive;
import com.github.junrar.rarfile.FileHeader;
import com.google.common.primitives.Ints;
import lombok.extern.slf4j.Slf4j;
import net.sf.sevenzipjbinding.IInArchive;
import net.sf.sevenzipjbinding.SevenZip;
import net.sf.sevenzipjbinding.impl.RandomAccessFileInStream;
import org.apache.commons.lang3.StringUtils;

import java.io.*;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

/**
 * @author panmeng
 */
@Slf4j
public class FileUtil {
    private static int BUFFER = 2048;


    public static void main(String[] args) throws Exception {

        //unzip("F:/condition/测试专场.zip","F:/condition//");
        //unRar("F:/condition/测试专场.rar", "F:/condition//");
//        System.out.println(getFolderName("测试专场.zip"));
//        String str = "loT038";
//        str = str.replaceAll("[lotLOT]","" );
//        System.out.println(StringUtils.isNumeric(str));
        String folderPath="F:\\condition\\测试专场";
        File dir = new File(folderPath);
        if(dir.exists()){
            if(dir.isFile()){
                dir.delete();
            }else if(dir.isDirectory()){
                deleteDirectory(folderPath);
            }
        }

    }
    public static Integer getLotNum(String lotName) {
        String lotNo = lotName.replaceAll("[a-zA-Z]", "");
        return Ints.tryParse(lotNo);
    }
    public static String unzip(String srcPath, String targetDir) {
        String name = "/";
        try {
            BufferedOutputStream dest = null;
            BufferedInputStream is = null;
            ZipEntry entry;
            ZipFile zipfile = new ZipFile(srcPath, Charset.forName("GBK"));

            Enumeration dir = zipfile.entries();
            while (dir.hasMoreElements()) {
                entry = (ZipEntry) dir.nextElement();

                if (entry.isDirectory()) {
                    name = entry.getName();
                    name = name.substring(0, name.length() - 1);
                    File fileObject = new File(targetDir + name);
                    fileObject.mkdir();
                }
            }

            Enumeration e = zipfile.entries();
            while (e.hasMoreElements()) {
                entry = (ZipEntry) e.nextElement();
                if (entry.isDirectory()) {
                    continue;
                } else {
                    is = new BufferedInputStream(zipfile.getInputStream(entry));
                    int count;
                    byte[] dataByte = new byte[BUFFER];
                    FileOutputStream fos = new FileOutputStream(targetDir + entry.getName());
                    dest = new BufferedOutputStream(fos, BUFFER);
                    while ((count = is.read(dataByte, 0, BUFFER)) != -1) {
                        dest.write(dataByte, 0, count);
                    }
                    dest.flush();
                    dest.close();
                    is.close();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return name;
    }

    public static List<String> unRar(String rarPath, String dstDirectoryPath) throws IOException {
        IInArchive archive;
        RandomAccessFile randomAccessFile=new RandomAccessFile(rarPath, "r");;
        // 第一个参数是需要解压的压缩包路径,第二个参数参考JdkAPI文档的RandomAccessFile
        //r代表以只读的方式打开文本,也就意味着不能用write来操作文件
        archive = SevenZip.openInArchive(null,
                new RandomAccessFileInStream(randomAccessFile));
        int[] in = new int[archive.getNumberOfItems()];
        for(int i = 0;i<in.length;i++){
            in[i] = i;
        }
        archive.extract(in,false,new ExtractCallback(archive, dstDirectoryPath));
        archive.close();
        randomAccessFile.close();
        ///data/microService/data/offline_dzhd_pdf/pdf/1637724142062/
        log.info("rar文件电子回单解压目标文件夹为:{}",dstDirectoryPath);
        /*List<String> allFileList = getAllFile(dstDirectoryPath, false);

        ArrayList<String> resultFileList = new ArrayList<>();
        String startString;
        String endString;
        String fianllyString;
        for(String s :allFileList){
            if (s.startsWith("/")) {
                startString = s.substring(0, s.lastIndexOf("/"));
                endString = s.substring(s.lastIndexOf("/") + 1);
                fianllyString = startString + "/" + endString;
            } else {
                //windows系统去掉盘符
                s = s.substring(2);
                startString = s.substring(0, s.lastIndexOf("\\"));
                endString = s.substring(s.lastIndexOf("\\") + 1);
                fianllyString = startString + "/" + endString;
            }
            //log.info("rar文件电子回单解压前缀为:{}rar文件电子回单解压后缀为:{}", startString,endString);
            //解决liunx路径出现//导致文件路径错误
            fianllyString = fianllyString.replaceAll("//", "/");
            resultFileList.add(fianllyString);
        }
        log.info("rar电子回单解压文件路径为:{}",resultFileList);*/
        return null;
    }
    /**
     * 获取路径下的所有文件/文件夹
     * @param directoryPath 需要遍历的文件夹路径
     * @param isAddDirectory 是否将子文件夹的路径也添加到list集合中
     * @return
     */
    public static List<String> getAllFile(String directoryPath,boolean isAddDirectory) {
        List<String> list = new ArrayList<String>();
        File baseFile = new File(directoryPath);
        if (baseFile.isFile() || !baseFile.exists()) {
            return list;
        }
        File[] files = baseFile.listFiles();
        for (File file : files) {
            if (file.isDirectory()) {
                if(isAddDirectory){
                    list.add(file.getAbsolutePath());
                }
                list.addAll(getAllFile(file.getAbsolutePath(),isAddDirectory));
            } else {
                list.add(file.getAbsolutePath());
            }
        }
        return list;
    }

    public static String judgeFileSuffix(String fileName) {
        if(StringUtils.isEmpty(fileName)){
            return null;
        }
        if(fileName.lastIndexOf(".") != -1 && fileName.lastIndexOf(".") != 0){
            String suffix =fileName.substring(fileName.lastIndexOf(".")+1);
            if("zip".equals(suffix)){
                return "zip";
            }else if("rar".equals(suffix)){
                return "rar";
            }else{
                return null;
            }
        }
        return null;
    }

    public static String getFolderName(String fileName) {
        if(StringUtils.isEmpty(fileName)){
            return null;
        }
        if(fileName.lastIndexOf(".") != -1 && fileName.lastIndexOf(".") != 0){
            return fileName.substring(0,fileName.lastIndexOf("."));
        }
        return null;
    }
    public static boolean deleteFile(String fileName) {
        File file = new File(fileName);
        if (file.isFile() && file.exists()) {
            file.delete();
            log.info("删除文件成功:{}",fileName);
            return true;
        } else {
            log.info("删除文件失败:{}",fileName);
            return false;
        }
    }
    private static boolean deleteDirectory(String directory) {
        if (!directory.endsWith(File.separator)) {
            directory = directory + File.separator;
        }
        File directoryFile = new File(directory);
        // 判断directory对应的文件是否存在,或者是否是一个文件夹
        if (!directoryFile.exists() || !directoryFile.isDirectory()) {
            log.info("文件夹删除失败,文件夹{}不存在" , directory);
        }
        boolean flag = true;
        // 删除文件夹下的所有文件和文件夹
        File[] files = directoryFile.listFiles();
        for (int i = 0; i < files.length; i++) {  // 循环删除所有的子文件及子文件夹
            // 删除子文件
            if (files[i].isFile()) {
                flag = deleteFile(files[i].getAbsolutePath());
                if (!flag) {
                    break;
                }
            } else {  // 删除子文件夹
                flag = deleteDirectory(files[i].getAbsolutePath());
                if (!flag) {
                    break;
                }
            }
        }
        if (!flag) {
            log.info("文件夹删除文件失败:{}",directory);
            return false;
        }
        // 最后删除当前文件夹
        if (directoryFile.delete()) {
            log.info("文件夹删除文件成功:{}",directory);
            return true;
        } else {
            log.info("文件夹删除文件失败:{}",directory);
            return false;
        }
    }
        /*public static File unRar(String srcPath,String outDir) throws Exception {
            File outFileDir = new File(outDir);
            if (!outFileDir.exists()) {
                boolean isMakDir = outFileDir.mkdirs();
                if (isMakDir) {
                    System.out.println("创建压缩目录成功");
                }
            }
            File rarFile=new File(srcPath);
            Archive archive = new Archive(new FileInputStream(rarFile));
            FileHeader fileHeader = archive.nextFileHeader();
            File out = null;
            while (fileHeader != null) {
                if (fileHeader.isDirectory()) {
                    fileHeader = archive.nextFileHeader();
                    continue;
                }
                out = new File(outDir + fileHeader.getFileNameString());
                if (!out.exists()) {
                    if (!out.getParentFile().exists()) {
                        out.getParentFile().mkdirs();
                    }
                    out.createNewFile();
                }
                FileOutputStream os = new FileOutputStream(out);
                archive.extractFile(fileHeader, os);

                os.close();
                break;
            }
            archive.close();
            return out;
        }*/
        public static String getFileSuffix(String fileName) {
            if(StringUtils.isEmpty(fileName)){
                return null;
            }
            if(fileName.lastIndexOf(".") != -1 && fileName.lastIndexOf(".") != 0){
                String suffix =fileName.substring(fileName.lastIndexOf(".")+1);
                return suffix;
            }
            return null;
        }

    public static void unRarFile(String srcRarPath, String dstDirectoryPath) {
        File dstDirectory = new File(dstDirectoryPath);
        if (!dstDirectory.exists()) {
            // 目标目录不存在时,创建该文件夹
            dstDirectory.mkdirs();
        }
        Archive a = null;
        try {
            InputStream in = new FileInputStream(new File(srcRarPath));
            a = new Archive(in);
            if (a != null) {
                a.getMainHeader().print(); // 打印文件信息.
                FileHeader fh = a.nextFileHeader();
                while (fh != null) {
                    if (fh.isDirectory()) {
                        // 文件夹
                        File fol = new File(dstDirectoryPath + File.separator + fh.getFileNameString());
                        fol.mkdirs();
                    } else { // 文件
                        File out = new File(dstDirectoryPath + File.separator + fh.getFileNameString().trim());
                        try {
                            // 之所以这么写try,是因为万一这里面有了异常,不影响继续解压.
                            if (!out.exists()) {
                                if (!out.getParentFile().exists()) {
                                    // 相对路径可能多级,可能需要创建父目录.
                                    out.getParentFile().mkdirs();
                                }
                                out.createNewFile();
                            }
                            FileOutputStream os = new FileOutputStream(out);
                            a.extractFile(fh, os);
                            os.close();
                        } catch (Exception ex) {
                            ex.printStackTrace();
                        }
                    }
                    fh = a.nextFileHeader();
                }
                a.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

ExtractCallback回调类

import net.sf.sevenzipjbinding.*;

import java.io.*;

public class ExtractCallback implements IArchiveExtractCallback {

    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;
        final String path = (String) inArchive.getProperty(index, PropID.PATH);
        final boolean isFolder = (boolean) inArchive.getProperty(index, PropID.IS_FOLDER);
        final String[] oldPath = {""};
        return new ISequentialOutStream() {
            public int write(byte[] data) throws SevenZipException {
                try {
                    if (!isFolder) {
//                        System.out.println(path);
                        File file = new File(ourDir+File.separator + path);
                        if (path.equals(oldPath[0])){
                            save2File(file, data,true);
                        }else{
                            save2File(file, data,false);
                        }
                        oldPath[0] = path;
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
                return data.length;
            }
        };
            /*return data -> {
                try {
                    if (!isFolder) {
                        File file = new File(ourDir + path);
                        save2File(file, data);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
                return data.length;
            };*/

    }

    @Override
    public void prepareOperation(ExtractAskMode arg0) throws SevenZipException {
    }

    @Override
    public void setOperationResult(ExtractOperationResult extractOperationResult) throws SevenZipException {

    }
    //解决字节丢失  未验证
    public boolean save2File(File file, byte[] msg,boolean append) {
        OutputStream fos = null;
        try {
            File parent = file.getParentFile();
            boolean bool;
            if ((!parent.exists()) && (!parent.mkdirs())) {
                return false;
            }
            //            fos = new FileOutputStream(file);
            fos = new FileOutputStream(file,append);//是否追加
            fos.write(msg);
            fos.flush();
            return true;
        } catch (FileNotFoundException e) {
            return false;
        } catch (IOException e) {
            File parent;
            return false;
        } finally {
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                }
            }
        }
    }

    public static boolean save2File(File file, byte[] msg) {
        OutputStream fos = null;
        try {
            File parent = file.getParentFile();
            if ((!parent.exists()) && (!parent.mkdirs())) {
                return false;
            }
            fos = new FileOutputStream(file, true);
            fos.write(msg);
            fos.flush();
            return true;
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            return false;
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        } finally {
            try {
                fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}



亲测,rar4和rar5两种版本的都可以解压

但是后来发现解压缩zip包的时候,如果是mac系统会出现乱码情况,因为mac系统zipFile默认是utf8编码格式,但是window认gbk编码格式,所以mac文件到使用gbk就会出现乱码格式,因此需要使用同时兼容多种操作协同的读取方式

使用

<dependency>
    <groupId>org.apache.ant</groupId>
    <artifactId>ant</artifactId>
    <version>1.10.10</version>
</dependency>

ZipFile文件格式进行处理即可解决

public static void unzip(String srcPath, String destDirPath) {
        File srcFile=new File(srcPath);
        if (!srcFile.exists()) {
            throw new RuntimeException(srcFile.getPath() + "所指文件不存在");
        }
        // 开始解压
        ZipFile zipFile = null;
        try {
            zipFile = new ZipFile(srcFile);
//            zipFile = new ZipFile(srcFile, Charset.forName("GBK"));  //含有中文 使用java.util.zip才需要指定这个,后面即使指定了也还是有问题,所以放弃这个改成Ant.jar
            Enumeration<?> entries = zipFile.getEntries();
            while (entries.hasMoreElements()) {
                ZipEntry entry = (ZipEntry) entries.nextElement();
                System.out.println("解压" + entry.getName());
                // 如果是文件夹,就创建个文件夹
                if (entry.isDirectory()) {
                    String dirPath = destDirPath + "/" + entry.getName();
                    File dir = new File(dirPath);
                    dir.mkdirs();
                } else {
                    // 如果是文件,就先创建一个文件,然后用io流把内容copy过去
                    File targetFile = new File(destDirPath + "/" + entry.getName());
                    // 保证这个文件的父文件夹必须要存在
                    if (!targetFile.getParentFile().exists()) {
                        targetFile.getParentFile().mkdirs();
                    }
                    targetFile.createNewFile();
                    // 将压缩文件内容写入到这个文件中
                    InputStream is = zipFile.getInputStream(entry);
                    FileOutputStream fos = new FileOutputStream(targetFile);
                    int len;
                    byte[] buf = new byte[2048];
                    while ((len = is.read(buf)) != -1) {
                        fos.write(buf, 0, len);
                    }
                    // 关流顺序,先打开的后关闭
                    fos.close();
                    is.close();
                }
            }
        } catch (Exception e) {
            log.error("解析压缩包文件异常:{}",srcPath);
            throw new RuntimeException("unzip error from ZipUtils", e);
        } finally {
            if (zipFile != null) {
                try {
                    zipFile.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐