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后面表示这个压缩文件的密码
谢语
非常感谢能看到最后,希望大家可以互相学习,也希望大家及时评论上方文章的错误之处,或提出不明白的地方,我看到后会第一时间处理。