Java 代码实现rar解压最全攻略操作

摘要:
最完整的Java代码实现了rar解压缩操作。首先,感谢您对以下链接的支持。写这个博客的原因主要是为了总结,并为第一次实现这个功能的学生提供一个完整的参考。第一次,我们需要在代码中实现rar和zip的解压缩操作。但rar的解压,尤其是5.0及以上版本的解压,困扰了我很长一段时间。根据这些博主的想法,我们最终通过组合rar文件实现了对rar文件的解压缩。

最全Java 代码实现rar解压操作
首先,非常感谢下面几位链接上的支持,之所以写这篇博文,主要在于总结,同时给第一次实现该功能的同学提供完整的参考。
因为第一次遇到需要在代码中实现rar和zip的解压操作。而zip其实很简单,jdk自带的ZipUtil就可以实现,这里不做赘述。但是rar的解压,特别是5.0及其以上版本的解压,折腾了我很久。根据这几位博主的思路,结合起来最终实现了对rar文件的解压。
unrar linux的安装:https://blog.51cto.com/lan2003/770497
rar的软件解压方式 :http://www.xitongzhijia.net/xtjc/20150513/48197.html
rar的第三方jar包解压方式:https://blog.csdn.net/fakergoing/article/details/82260699

一、通过[com.github.junrar]实现winrar5.0以下版本解压
1、首先贴出来maven依赖,这里使用的是最高版本4.0,但是依然无法解决5.0及其以上的版本问题。

<!-- https://mvnrepository.com/artifact/com.github.junrar/junrar -->
<dependency>
    <groupId>com.github.junrar</groupId>
    <artifactId>junrar</artifactId>
    <version>4.0.0</version>
</dependency>

2、代码实现:优化了https://blog.csdn.net/fakergoing/article/details/82260699中的linux中无法识别问题

/**
     * 根据原始rar路径,解压到指定文件夹下
     * 这种方法只能解压rar 5.0版本以下的,5.0及其以上的无法解决
     *
     * @param srcRarPath       原始rar路径+name
     * @param dstDirectoryPath 解压到的文件夹
     */
    public static String unRarFile(String srcRarPath, String dstDirectoryPath) throws Exception {
        log.debug("unRarFile srcRarPath:{}, dstDirectoryPath:{}", srcRarPath, dstDirectoryPath);
        if (!srcRarPath.toLowerCase().endsWith(".rar")) {
            log.warn("srcFilePath is not rar file");
            return "";
        }
        File dstDiretory = new File(dstDirectoryPath);
        // 目标目录不存在时,创建该文件夹
        if (!dstDiretory.exists()) {
            dstDiretory.mkdirs();
        }
        // @Cleanup Archive archive = new Archive(new File(srcRarPath));  com.github.junrar 0.7版本jarAPI
        @Cleanup Archive archive = new Archive(new FileInputStream(new File(srcRarPath)));
        if (archive != null) {
            // 打印文件信息
            archive.getMainHeader().print();
            FileHeader fileHeader = archive.nextFileHeader();
            while (fileHeader != null) {
                // 解决中文乱码问题【压缩文件中文乱码】
                String fileName = fileHeader.getFileNameW().isEmpty() ? fileHeader.getFileNameString() : fileHeader.getFileNameW();
                // 文件夹
                if (fileHeader.isDirectory()) {
                    File fol = new File(dstDirectoryPath + File.separator + fileName.trim());
                    fol.mkdirs();
                } else { // 文件
                    // 解决linux系统中分隔符无法识别问题
                    String[] fileParts = fileName.split("\\");
                    StringBuilder filePath = new StringBuilder();
                    for (String filePart : fileParts) {
                        filePath.append(filePart).append(File.separator);
                    }
                    fileName = filePath.substring(0, filePath.length() - 1);
                    File out = new File(dstDirectoryPath + File.separator + fileName.trim());
                    if (!out.exists()) {
                        // 相对路径可能多级,可能需要创建父目录.
                        if (!out.getParentFile().exists()) {
                            out.getParentFile().mkdirs();
                        }
                        out.createNewFile();
                    }
                    @Cleanup FileOutputStream os = new FileOutputStream(out);
                    archive.extractFile(fileHeader, os);
                }
                fileHeader = archive.nextFileHeader();
            }
        } else {
            log.warn("rar file decompression failed , archive is null");
        }
        return dstDirectoryPath;
    }

3、该方法弊端

最大的问题就在于无法实现winrar5.0及其以上版本的解压问题:WinRAR5之后,在rar格式的基础上,推出了另一种rar,叫RAR5,winrar官方并没有开源算法,jar包无法解析这种格式。
咱们先看一段源码

case MarkHeader:
    this.markHead = new MarkHeader(block);
    if (!this.markHead.isSignature()) {
        if (this.markHead.getVersion() == RARVersion.V5) {
            logger.warn("Support for rar version 5 is not yet implemented!");
            throw new RarException(RarExceptionType.unsupportedRarArchive);
        }

        throw new RarException(RarExceptionType.badRarArchive);
    }

    this.headers.add(this.markHead);
    break;

这是junrar的主类Archive中的rar版本判断语句,这里明确说明了对于5.0版本尚未实现。并且抛出了RarException的异常。

二、linux中安装unrar软件
1、unrar安装包
linux 32位:http://www.rarlab.com/rar/rarlinux-5.3.b4.tar.gz
linux 64位:http://www.rarlab.com/rar/rarlinux-x64-5.3.b4.tar.gz
由于是国外源,所以下载速度极慢,很可能下载不成功。

还有一种最简单的安装方式【使用yum安装】:

rpm -ivh http://mirrors.whsir.com/centos/whsir-release-centos.noarch.rpm

yum install rar

2、linux中安装unrar

①上传unrar到linux服务器 

如 /usr 路径

②解压到指定路径:

tar -zxf /usr/rarlinux-x64-5.7.1.tar.gz -C /usr/local/

③建立软连接:必须要有软连接,类似于jdk的环境变量,保证可以在任意目录下使用rar和unrar命令

ln -s /usr/local/rar/rar /usr/local/bin/rar
ln -s /usr/local/rar/unrar /usr/local/bin/unrar

④测试是否创建成功

**在任意路径输入下列命令**
rar
unrar
**出现如下信息表示安装成功**
RAR 5.71   Copyright (c) 1993-2019 Alexander Roshal   28 Apr 2019
Trial version             Type 'rar -?' for help

3、Java中实现

/**
* 采用命令行方式解压文件
* @param multipartFile 压缩文件
* @param fileName 解压文件名称
* @return
*/
public RequestResult realExtractRar(MultipartFile multipartFile, String fileName) {
RequestResult result = RequestResult.success();
try {
String filePath = zipPath + "test1/";

File file = new File(zipPath);
file.mkdirs();
File fileDir = new File(filePath);
fileDir.mkdirs();
File saveFile = new File(fileDir, fileName);//将压缩包解析到指定位置
multipartFile.transferTo(saveFile);
// 获取windows中 WinRAR.exe的路径
boolean bool = false;
boolean isWin = System.getProperty("os.name").toLowerCase().contains("win");
final boolean isLinux = System.getProperty("os.name").toLowerCase().indexOf("linux") >= 0;

// 开始调用命令行解压,参数-o+是表示覆盖的意思
String cmd ="";
if(isWin) {
cmd = winRarPath + " X -o+ " + saveFile + " " + filePath;
}else if(isLinux){
//如果linux做了软连接 不需要这里配置路径
String cmdPath = "/usr/local/bin/unrar";
cmd = "rar" + " X -o+ " + saveFile + " " + filePath;
}
Process proc = Runtime.getRuntime().exec(cmd);
if (proc.waitFor() != 0) {
if (proc.exitValue() == 0) {
bool = false;
}
} else {
bool = true;
}
System.out.println("解压" + (bool ? "成功" : "失败"));

if (bool) {
String filePath1 = filePath + fileName.substring(0, fileName.indexOf("."));
result = getFiles(filePath1);
}else{
result = RequestResult.error("上传rar压缩包解压失败!");
}
}catch (Exception e) {
e.printStackTrace();
result = RequestResult.error("上传文件异常,异常原因:" + e.getMessage());
}finally {
//删除文件和文件压缩包
FileUtils.DeleteFolder(zipPath);
}

return result;
}

/*
* 通过递归得到某一路径下所有的目录及其文件
*/
private RequestResult getFiles(String filePath) {
RequestResult result = RequestResult.success();
try {
File srcfile = new File(filePath);
File[] files = srcfile.listFiles();
if (srcfile.exists()) {
if (files.length == 0) {
result = RequestResult.error("上传文件夹是空的!");
} else {
for (File pdffile : files) {
if (pdffile.isDirectory()) {
/*
* 递归调用
*/
getFiles(pdffile.getAbsolutePath());
} else {
String name = pdffile.getName();
// File转MultipartFile
FileInputStream input = new FileInputStream(pdffile);
MultipartFile multipartFile1 = new MockMultipartFile("file", name, "text/plain", IOUtils.toByteArray(input));

uploadDazlFromPdf(multipartFile1, name);

input.close();
}
}
}
} else {
result = RequestResult.error("上传文件解压失败!");
}
}catch (Exception e){
e.printStackTrace();
result = RequestResult.error("上传文件异常,异常原因:" + e.getMessage());
}finally {
//删除文件和文件压缩包
FileUtils.DeleteFolder(zipPath);
}
return result;
}

4、关于Process proc = Runtime.getRuntime().exec(cmd);命令的补充说明

// 需要指定参数一:命令位置;参数二:-c表示先执行第一个参数;参数三:你的命令。
Runtime.getRuntime().exec(new String[]{"/bin/sh","c","xxx"});
// 如果执行了上面第三步,可以任意目录使用rar和unrar命令,则可以省略第一和第二个参数,直接使用第三个参数

5、关于unrar在linux中的命令说明

#解压
unrar x abc.rar 表示解压到同一个目录文件夹
unrar e abc.rar 解压出来是散开的

解压:rar x FileName.rar
压缩:rar a FileName.rar DirName

最后:此文章来源

https://blog.csdn.net/weixin_42418785/article/details/90344053?utm_medium=distribute.pc_relevant.none-task-blog-2~default~baidujs_utm_term~default-1.control&spm=1001.2101.3001.4242

特此记录一遍后续使用方便

免责声明:文章转载自《Java 代码实现rar解压最全攻略操作》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Linux下安装MavenJava生成excel导出文件(使用poi+JXL)下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Lua字符串及模式匹配

字符类基础函数举例介绍: string.len( ‘string’ ) string.lower( ‘string’ ) string.upper( ‘string’ ) string.rep( ‘a’ , 5 ) ==> aaaaa string.sub( ‘string’ , I , j ) string.sub(...

wpf mvvm模式下 在ViewModel关闭view

本文只是博主用来记录笔记,误喷 使用到到了MVVM中消息通知功能 第一步:在需要关闭窗体中注册消息   1 public UserView() 2 { 3 this.DataContext = new UserViewModel(); 4 InitializeComponent();...

java 数据库读取工具类(读取config.properties配置文件)

数据库读取工具类 1 package com.db; 2 3 import java.sql.Connection; 4 import java.sql.DriverManager; 5 import java.sql.SQLException; 6 import oracle.jdbc.driver.OracleDriver; 7...

Android 显示 WebView ,加载URL 时,向webview的 header 里面传递参数

1.主要布局 <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/too...

封装两个简单的Jquery组件

Jquery给我们提供了很大的方便,我们把他看成是一个公共库,以致在这个公共库上延伸出了很多Jquery插件;在项目过程中,有些插件总是不那么令人满意; 主要说两个项目用途: 1、 遮罩层,跟一般的遮罩层不一样,我需要实现的是对某一个元素进行局部遮罩; 2、 冒泡提示,网上有很多,我需要的只是一种在页面指定位置弹出来的一个静止定位的div而已;两个就自己了...

Java自学-类和对象 传参

Java中的传参 变量有两种类型 基本类型 和类类型 参数也是变量,所以传参分为基本类型传参类类型传参 步骤 1 : 基本类型传参 基本类型传参在方法内,无法修改方法外的基本类型参数 public class Hero { String name; //姓名 float hp; //血量...