实现java 解压zip,rar(rar5)以及调用命令解压,搬运即用哦,内含jar包

前言

最近项目需要解压zip,rar,文件,然后将解压后的pdf解析入库,整了一个多星期记录一下,方便以后使用。

一、解压zip文件到指定文件夹

package com.skysz.app.cb.utils;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

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


public class UZipFile{
    private static Log log = LogFactory.getLog(UZipFile.class);

    /**
     * 解压文件
     */
    @SuppressWarnings("rawtypes")
    public static List<String> unZipFiles(File zipFile , String descDir)throws IOException{
        List<String> pathList = new ArrayList<>();
        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();
            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;
            }
            //输出文件路径信息
            pathList.add(outPath);
            log.info("解压文件路径为:"+outPath);
            OutputStream out = new FileOutputStream(outPath);
            byte[] buf1 = new byte[1024];
            int len;
            while((len=in.read(buf1))>0)
            {
                out.write(buf1,0,len);
            }
            in.close();
            out.close();
        }
        log.info("******************解压完毕********************");
        return pathList;

    }

    public static void main(String[] args) throws IOException {
        /**
         * 解压文件
         */
        File zipFile = new File("E:\\项目文件\\中合担保标准回单模板\\银行回单.zip");
        String descDir = "E:\\11\\";
        unZipFiles(zipFile,descDir);
    }
}

执行结果为:

09:28:25.234 [main] INFO com.skysz.app.cb.utils.UZipFile - 解压文件路径为:E:\11\银行回单/1.建行--银企直连账户.pdf
09:28:25.241 [main] INFO com.skysz.app.cb.utils.UZipFile - 解压文件路径为:E:\11\银行回单/1.建行.pdf
09:28:25.244 [main] INFO com.skysz.app.cb.utils.UZipFile - 解压文件路径为:E:\11\银行回单/1建行.pdf
09:28:25.247 [main] INFO com.skysz.app.cb.utils.UZipFile - ******************解压完毕****************************************

Process finished with exit code 0

解压后的文件

1.1所需pom文件

不需要引入pom,主要依赖于jdk

二、解压rar文件到指定文件夹(只支持5以下)

package com.util;


import de.innosystec.unrar.Archive;
import de.innosystec.unrar.exception.RarException;
import de.innosystec.unrar.rarfile.FileHeader;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;



public class UnRARUtil {

    private static Log log = LogFactory.getLog(UnRARUtil.class);

    /**

     * @param  args

     * @throws  IOException

     * @throws  RarException

     */

    public static void main(String[] args) throws RarException, IOException {
        //压缩文件
        String rarPath = "E:\\项目文件\\中合担保标准回单模板\\rar4.2压缩包\\银行回单.rar";
        //解压到这个目录
        String dstDirectoryPath = "E:\\11\\"+System.currentTimeMillis();

        unrarFile(rarPath,dstDirectoryPath);

    }


    public static void unrarFile(String rarPath, String dstDirectoryPath) throws IOException, RarException {
        File dstDiretory = new File(dstDirectoryPath);

        if (!dstDiretory.exists()) {
            dstDiretory.mkdirs();
        }
        Archive a = new Archive(new File(rarPath));
        ArrayList<String> filepathList = new ArrayList<>();

        if (a != null) {

            a.getMainHeader().print(); //打印文件信息.

            FileHeader fh = a.nextFileHeader();

//            fileName=  fh.getFileNameW().trim();
//            if(!existZH(fileName)){
//                fileName = fh.getFileNameString().trim();
//            }
            while (fh != null) {
                // 判断编码,解决中文乱码的问题
                String localpath = fh.isUnicode() ? fh.getFileNameW() : fh.getFileNameString();
                //文件

                File out = new File(dstDirectoryPath + File.separator + localpath.trim());
                String outPath = out.getAbsolutePath().replaceAll("\\*", "/");;
                //判断路径是否存在,不存在则创建文件路径
                File file = new File(outPath.substring(0, outPath.lastIndexOf('\\')));
                if(!file.exists())
                {
                    file.mkdirs();
                }
                //判断文件全路径是否为文件夹,如果是上面已经上传,不需要解压
                if(new File(outPath).isDirectory())
                {
                    break;
                }
                //输出文件路径信息
                if(fh != null){
                    filepathList.add(out.getAbsolutePath());
                }
                FileOutputStream os = new FileOutputStream(out);

                a.extractFile(fh, os);

                os.close();

                fh = a.nextFileHeader();

            }

        }

        a.close();
        System.out.println(filepathList);
    }

}

2.1所需pom文件,这里我使用离线jar包形式(pom添加)

下载地址:
http://www.java2s.com/Code/JarDownload/java/java-unrar-0.3.jar.zip
<dependency>
		  <groupId>unrar</groupId>
		  <artifactId>java-unrar</artifactId>
		  <version>0.3</version>
		  <scope>system</scope>
		  <systemPath>${basedir}/lib/java-unrar-0.3.jar</systemPath>
	  </dependency>
    <dependency>

文件夹和src同级目录下创建lib
在这里插入图片描述

解压rar5以下效果

SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
[E:\11\1638413671304\银行回单\1.建行--银企直连账户.pdf, E:\11\1638413671304\银行回单\1.建行.pdf, E:\11\1638413671304\银行回单\1建行.pdf]

解压后文件路径截图
在这里插入图片描述

当解压rar5的时候会抛出下面异常

SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
十二月 02, 2021 10:44:58 上午 de.innosystec.unrar.Archive setFile
警告: exception in archive constructor maybe file is encrypted or currupt
de.innosystec.unrar.exception.RarException: badRarArchive
	at de.innosystec.unrar.Archive.readHeaders(Archive.java:238)
	at de.innosystec.unrar.Archive.setFile(Archive.java:122)
	at de.innosystec.unrar.Archive.<init>(Archive.java:106)
	at de.innosystec.unrar.Archive.<init>(Archive.java:96)
	at com.util.UnRARUtil.unrarFile(UnRARUtil.java:48)

这是因为rar5的压缩算法和rar4的压缩算法不一致,rar5并不是开源的,下面是java解压rar5,原文出自
链接: link.
但也是存在一些问题,我下面会提出来

三、java解压rar(同时兼容5,及以下)

package com.util;


import net.sf.sevenzipjbinding.IInArchive;
import net.sf.sevenzipjbinding.SevenZip;
import net.sf.sevenzipjbinding.impl.RandomAccessFileInStream;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.util.List;

public class RAR5Util {
    public static void main(String[] args) throws IOException {
        String rarDir = "E:\\项目文件\\中合担保标准回单模板\\rar5压缩包\\银行回单.rar";
        String outDir = "E:\\12\\";
        unRar(new File(rarDir),outDir);
    }
    public static List<String> unRar(File rarPath, String dstDirectoryPath) throws IOException {
        IInArchive archive;
        RandomAccessFile randomAccessFile;
        // 第一个参数是需要解压的压缩包路径,第二个参数参考JdkAPI文档的RandomAccessFile
        //r代表以只读的方式打开文本,也就意味着不能用write来操作文件
        randomAccessFile = new RandomAccessFile(rarPath, "r");
        archive = SevenZip.openInArchive(null, // null - autodetect
                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/
        System.out.println("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("/") || 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;
            }
            System.out.println("rar文件电子回单解压前缀为:"+startString+"rar文件电子回单解压后缀为:"+endString);
            //解决liunx路径出现//导致文件路径错误
            fianllyString = fianllyString.replaceAll("//","/");
            resultFileList.add(fianllyString);
        }
        System.out.println("rar电子回单解压文件路径为"+resultFileList);
        return resultFileList;
    }
    /**
     * 获取路径下的所有文件/文件夹
     * @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;
    }

}

上文引入ExtractCallback类如下

package com.util;

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+"\\" + 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();
                }
            }
        }
    }


3.1所需pom文件

<!--		解压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,所需依赖结束-->

运行结果如下

Connected to the target VM, address: '127.0.0.1:49400', transport: 'socket'
rar文件电子回单解压目标文件夹为:E:\12\
rar文件电子回单解压前缀为:\12\银行回单rar文件电子回单解压后缀为:1.建行--银企直连账户.pdf
rar文件电子回单解压前缀为:\12\银行回单rar文件电子回单解压后缀为:1.建行.pdf
rar文件电子回单解压前缀为:\12\银行回单rar文件电子回单解压后缀为:1建行.pdf
rar电子回单解压文件路径为[\12\银行回单/1.建行--银企直连账户.pdf, \12\银行回单/1.建行.pdf, \12\银行回单/1建行.pdf]
Disconnected from the target VM, address: '127.0.0.1:49400', transport: 'socket'

Process finished with exit code 0

文件相应位置
在这里插入图片描述
报错一、
报异常系统c盘有一个dll文件正在使用,也就是如果windows连接两台liunx服务器代码,同时进行解压操作,后面的执行就会报错!
Caused by: java.io.FileNotFoundException: C:\Users\ADMINI~1.DES\AppData\Local\Temp\SevenZipJBinding-0EsPGE1ZKaCb\lib7-Zip-JBinding.dll (另一个程序正在使用此文件,进程无法访问。)
我个人理解其实这个影响不大
报错二、
此代码有个bug,会使得字节损失。当读入多个byte[]时,save2File(file, data)只会写入最后的byte[]
报错三、
在liunx环境,解压的文件会莫名其妙在文件的上级文件夹多一个\(比如我创建文件夹1234,然后1234文件夹下有个1.pdf,压缩为pdf.rar 。解压后1234的文件夹会多一个\)导致后期处理文件非常不方便,这个也许是我个人使用问题,但是在Windows没有问题,因为时间紧迫,我直接放弃了java解压rar
使用的是调用liunx文件服务器命令解压

本文中报错二已解决,也是原文出处评论下的方法

四、解压rar5调用liunx 程序unrar

原文出处链接: link.
安装支持库
yum install -y gcc gcc-c++ autoconf wget
二、安装RAR
1.下载rar源码包
wget http://www.rarlab.com/rar/rarlinux-x64-5.3.0.tar.gz
2.解压安装
tar -zxvf rarlinux-x64-5.3.0.tar.gz
cd rar
make && make install
/bin/cp -f rar_static /usr/local/bin/rar && /bin/cp -f rar_static /usr/local/bin/unrar
cd …
rm -rf rar
代码如下

package com.skysz.app.cb.utils;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

/**
 * RAR 5.0以上调用命令解压
 * @author liuyazhuang
 *
 */
@Component
public class RarToFile {
    private static Log log = LogFactory.getLog(RarToFile.class);
    private final static String descDir = "/tempClient/";
    private final static String fileName = "/tempClient/123456789012345677890_123456789012345.rar";
    public static void main(String[] args) {

    }
    //    每5秒
//    @Scheduled(cron = "0/20 * * * * ?")
    public void testRarUtil(){
        System.out.println("开始解压----------------------------------");
        List<String> strings = unRARFile(fileName, descDir);
        System.out.println("文件夹列表:"+strings);
        System.out.println("解压完毕----------------------------------");
    }
    /*
     * cmd 压缩与解压缩命令
     */
    private static String rarCmd = "rar a ";
    private static String unrarCmd = "rar x ";

    /**
     * 将1个文件压缩成RAR格式
     * rarName 压缩后的压缩文件名(不包含后缀)
     * fileName 需要压缩的文件名(必须包含路径)
     * destDir 压缩后的压缩文件存放路径
     */
    public static void RARFile(String rarName, String fileName, String destDir) {
        rarCmd += destDir + rarName + ".rar " + fileName;
        try {
            Runtime rt = Runtime.getRuntime();
            Process p = rt.exec(rarCmd);
        }catch(Exception e) {
            System.out.println(e.getMessage());
        }
    }

    /**
     * 将1个RAR文件解压
     * rarFileName 需要解压的RAR文件(必须包含路径信息以及后缀)
     * destDir 解压后的文件放置目录
     */
    public static List<String> unRARFile(String rarFileName, String destDir) {
        List<String> allFile = new ArrayList<>();
        File pathFile = new File(destDir);
        if(!pathFile.exists()){
            pathFile.mkdirs();
        }
        log.info("开始调用rar工具解压-------,压缩包文件路径:"+rarFileName+"目标文件夹路径为:"+destDir);
        unrarCmd ="rar x "+ rarFileName + " " + destDir;
        try {
            Runtime rt = Runtime.getRuntime();
            Process p = rt.exec(unrarCmd);
            log.info("解压RAR unrarCmd:"+unrarCmd);
            int exitVal = p.waitFor();
            if(exitVal== 0){
                allFile= getAllFile(destDir, false);
            }else{
                log.error("调用命令解压失败");
            }
            log.info("解压所有文件夹路径list:"+allFile);
            return  allFile;
        } catch (Exception e) {
            System.out.println(e.getMessage());
            log.error("解压RAR错误!");
        }
        return  allFile;

    }

    /**
     * 获取路径下的所有文件/文件夹
     * @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;
    }
}

这个调用日志我就不展示了,不太好操作,但肯定没有问题,回归测试完毕,即将上生产

4.1所需pom文件

主要依赖jdk

4.2简单解压命令,可根据实际情况改变调用命令

rar -y x -p123456 test.rar 解压带密码的rar文件
-y表示安静模式
x表示解压
-p后面表示这个压缩文件的密码

谢语

非常感谢能看到最后,希望大家可以互相学习,也希望大家及时评论上方文章的错误之处,或提出不明白的地方,我看到后会第一时间处理。

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值