java压缩和解压ZIP和RAR文件踩坑实践

该文章主要内容

1.引入依赖

<!-- 解压zip -->
<dependency>
    <groupId>org.apache.ant</groupId>
    <artifactId>ant</artifactId>
    <version>1.10.5</version>
</dependency>
<!-- 解压rar -->
<dependency>
    <groupId>com.github.axet</groupId>
    <artifactId>java-unrar</artifactId>
    <version>1.7.0-8</version>
</dependency>

2. 支持解压缩ZIP和winrar 5版本以上的RAR代码

import com.github.junrar.Archive;
import com.github.junrar.rarfile.FileHeader;
import org.apache.tools.zip.ZipEntry;
import org.apache.tools.zip.ZipFile;

import java.io.*;
import java.util.Enumeration;

public class UnZipAndRarUtil {

    // 获取当前运行环境是win还是linux
    private static final boolean isLinux = System.getProperty("os.name").toLowerCase().indexOf("linux") >= 0;

    /**
     * 使用apache ant实现zip解压缩
     * @param sourceZip 压缩文件
     * @param outDir 解压结果路径
     * @throws IOException
     */
    public static void unZip(String sourceZip, String outDir) throws IOException {

        File outFileDir = new File(outDir);
        if (!outFileDir.exists()) {
            boolean isMakDir = outFileDir.mkdirs();
            if (isMakDir) {
                System.out.println("创建压缩目录成功");
            }
        }

        ZipFile zip = new ZipFile(new File(sourceZip));
        for (Enumeration enumeration = zip.getEntries(); enumeration.hasMoreElements(); ) {
            ZipEntry entry = (ZipEntry) enumeration.nextElement();
            String zipEntryName = entry.getName();
            InputStream in = zip.getInputStream(entry);

            if (entry.isDirectory()) {      //处理压缩文件包含文件夹的情况
                File fileDir = new File(outDir + zipEntryName);
                fileDir.mkdir();
                continue;
            }

            File file = new File(outDir, zipEntryName);
            file.createNewFile();
            OutputStream out = new FileOutputStream(file);
            byte[] buff = new byte[1024];
            int len;
            while ((len = in.read(buff)) > 0) {
                out.write(buff, 0, len);
            }
            in.close();
            out.close();
        }
    }

    /**
     * 使用junrar解压,只支持winrar 5以下解压缩
     * @param sourceRar 压缩文件
     * @param outDir 解压结果路径
     * @throws Exception
     */
    public static void unRar(String sourceRar, String outDir) throws Exception {
        File outFileDir = new File(outDir);
        if (!outFileDir.exists()) {
            boolean isMakDir = outFileDir.mkdirs();
            if (isMakDir) {
                System.out.println("创建压缩目录成功");
            }
        }
        Archive archive = new Archive(new FileInputStream(new File(sourceRar)));
        FileHeader fileHeader = archive.nextFileHeader();
        while (fileHeader != null) {
            if (fileHeader.isDirectory()) {
                fileHeader = archive.nextFileHeader();
                continue;
            }
            File 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();

            fileHeader = archive.nextFileHeader();
        }
        archive.close();
    }


    /**
     * 采用命令行方式解压文件,支持winrar 5以上解压缩
     * @param sourceRar 压缩文件
     * @param destDir 解压结果路径
     * @param cmdPath WinRAR.exe的路径,也可以在代码中写死
     * @return
     */
    public static boolean realExtract(String sourceRar, String destDir,String cmdPath) {
        File zipFile = new File(sourceRar);
        // 解决路径中存在/..格式的路径问题
        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;
                }
            }
        }

        boolean bool = false;
        if (!zipFile.exists()) {
            return false;
        }
        // 开始调用命令行解压,参数-o+是表示覆盖的意思
        cmdPath = "C:\\Program Files\\WinRAR\\WinRAR.exe";
        if (isLinux) {
            cmdPath = "/usr/local/bin/unrar";
        }
        String cmd = cmdPath + " X -o+ " + zipFile + " " + 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 ? "成功" : "失败"));
        return bool;
    }


    private static void unfile(String sourceFile, String destDir) throws Exception {
        // 根据类型,进行相应的解压缩
        String type = sourceFile.substring(sourceFile.lastIndexOf(".") + 1);
        if (type.toLowerCase().equals("zip")) {
            UnZipAndRarUtil.unZip(sourceFile, destDir);
        } else if (type.toLowerCase().equals("rar")) {
            UnZipAndRarUtil.realExtract(sourceFile, destDir, null);
        } else {
            System.out.println(type.toLowerCase());
            throw new RuntimeException("deCompress: 只支持zip和rar格式的压缩包!");
        }
    }

    /**
     * 解压到指定目录
     */
    public static void deCompress(String sourceFile, String destDir) throws Exception {
        if (sourceFile == null || destDir == null) {
            throw new RuntimeException("deCompress: 目录不能为空");
        }
        // 保证文件夹路径最后是"/"或者"\"
        char lastChar = destDir.charAt(destDir.length() - 1);
        if (lastChar != '/' && lastChar != '\\') {
            // 代码中拼接文件夹 / 建议都用File.separator规避系统不同系统影响
            destDir += File.separator;
        }
        unfile(sourceFile, destDir);
    }

    /**
     * 解压到指定目录
     */
    public static void deCompress(File sourceFile, String destDir) throws Exception {
        if (!sourceFile.exists() || sourceFile.isDirectory()) {
            throw new RuntimeException("deCompress: 文件不存在");
        }
        deCompress(sourceFile.getPath(), destDir);
    }

    /**
     * 解压到当前目录
     */
    public static void deCompress(String sourceFile) throws Exception {

        // 获得文件目录
        int i = sourceFile.lastIndexOf("/");
        int d = sourceFile.lastIndexOf("\\");
        if (i == -1 && d == -1) {
            throw new RuntimeException("deCompress: 目录separator异常");
        } else if (i == -1) {
            i = d;
        }
        String destDir = sourceFile.substring(0, i + 1);
        unfile(sourceFile, destDir);
    }

    /**
     * 解压到当前目录
     * @param sourceFile 当前文件路径
     * @throws Exception
     */
    public static void deCompress(File sourceFile) throws Exception {
        if (!sourceFile.exists() || sourceFile.isDirectory()) {
            throw new RuntimeException("deCompress: 文件不存在");
        }
        deCompress(sourceFile.getPath());
    }

    public static void main(String[] args) throws Exception {
        String zipFilepath = "E:\\自己\\test\\自己.rar";
        UnZipAndRarUtil.deCompress(new File(zipFilepath));
    }
}

3. 解压缩方式说明

3.1 ZIP可以使用 apache ant 实现文件压缩/解压缩

比较简单,暂不单独说明

3.2 winrar 5以下使用java-unrar解压缩,winrar 5需要使用命令解压缩

3.2.1 使用 java-unrar-0.3.jar解压缩

3.2.2 使用 junrar-3.0.0jar解压缩

    <!-- 解压rar -->
    <dependency>
        <groupId>com.github.junrar</groupId>
        <artifactId>junrar</artifactId>
        <version>3.0.0</version>
    </dependency>

junrar解压本质上都是使用的 java-unrar的解压缩能力,所以也只支持 winrar 5以下压缩文件

具体使用解压缩代码参考如下文章
java解压缩,支持rar和zip

使用java-unrar和junrar包解压会出现如下问题,
其一:如果压缩文件中有中文名字的文件夹,解压以后文件夹名字是乱码,但是不影响文件夹里面的文件;
其二:超过 WinRar5版本的 压缩 .rar 文件会无法解压,报错badRarArchive。
官方解释如下:

针对rar文件解压时报如此异常的可能原因是因为rar压缩算法是不开源的,导致这块资料相对较少,对高版本没有兼容性;
为避免不必要的如此文件解压异常,实际项目中若需要上传文件执行导入等相关功能时,可以强制限定文件格式为非rar格式,如zip开源算法,使用比较成熟就不会有这种尴尬的问题;

在这里插入图片描述

3.2.3 使用命令解压缩

目前找到的解压缩WinRar5版本以上最好的方法,使用该解压方式只需要配置win和linix的文件目录即可(用到哪种环境配置哪种)
在win版本使用,需要找到WinRAR.exe安装目录进行配置,
在linux中安装unrar默认路径是/usr/local/bin/unrar
目录位置可以提出在yml中配置,但是因为为了方便使用,暂时统一卸载代码中
在这里插入图片描述

3.3 Linux版本安装unrar

先安装unrar,然后调用unrar命令解压
1.安装unrar
wget https://www.rarlab.com/rar/rarlinux-x64-5.7.0.tar.gz 下载unrar包
tar -zxf rarlinux-x64-5.7.0.tar.gz
cd rar
make & make install
安装完成unrar,安装默认路径是/usr/local/bin
里面有rar 和 unrar可执行文件
/usr/local/bin/unrar,路径写这个路径即可,调用上述方法
在这里插入图片描述

参考如下文章:
java解压缩,支持rar和zip
com.github.junrar.exception.RarException: badRarArchive—rar5.0版解决方案

  • 9
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
Java提供了ZipInputStream和ZipOutputStream类来实现对zip文件解压缩和压缩,同时也提供了解压RAR文件的开源库,如junrar等。以下是一个示例代码,演示如何使用ZipInputStream和ZipEntry来解压zip文件: ```java import java.io.*; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; public class Unzip { public static void main(String[] args) throws IOException { String zipFilePath = "path/to/zip/file.zip"; String destDirectory = "path/to/destination/folder"; unzip(zipFilePath, destDirectory); } public static void unzip(String zipFilePath, String destDirectory) throws IOException { File destDir = new File(destDirectory); if (!destDir.exists()) { destDir.mkdir(); } ZipInputStream zipIn = new ZipInputStream(new FileInputStream(zipFilePath)); ZipEntry entry = zipIn.getNextEntry(); while (entry != null) { String filePath = destDirectory + File.separator + entry.getName(); if (!entry.isDirectory()) { extractFile(zipIn, filePath); } else { File dir = new File(filePath); dir.mkdir(); } zipIn.closeEntry(); entry = zipIn.getNextEntry(); } zipIn.close(); } private static void extractFile(ZipInputStream zipIn, String filePath) throws IOException { BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(filePath)); byte[] bytesIn = new byte[4096]; int read = 0; while ((read = zipIn.read(bytesIn)) != -1) { bos.write(bytesIn, 0, read); } bos.close(); } } ``` 对于RAR文件解压缩,可以使用开源库junrar: ```java import com.github.junrar.Archive; import com.github.junrar.exception.RarException; import com.github.junrar.impl.FileVolumeManager; import com.github.junrar.rarfile.FileHeader; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; public class Unrar { public static void main(String[] args) throws RarException, IOException { String rarFilePath = "path/to/rar/file.rar"; String destDirectory = "path/to/destination/folder"; unrar(rarFilePath, destDirectory); } public static void unrar(String rarFilePath, String destDirectory) throws RarException, IOException { Archive archive = new Archive(new FileVolumeManager(new File(rarFilePath))); FileHeader fileHeader = archive.nextFileHeader(); while (fileHeader != null) { String filePath = destDirectory + File.separator + fileHeader.getFileNameString().trim(); if (fileHeader.isDirectory()) { File dir = new File(filePath); dir.mkdirs(); } else { FileOutputStream fos = new FileOutputStream(new File(filePath)); archive.extractFile(fileHeader, fos); fos.close(); } fileHeader = archive.nextFileHeader(); } archive.close(); } } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值