废话不多说直接上代码
1.相关依赖pom
<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>
2.解压压缩文件工具类
import net.sf.sevenzipjbinding.IInArchive;
import net.sf.sevenzipjbinding.SevenZip;
import net.sf.sevenzipjbinding.impl.RandomAccessFileInStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.nio.charset.Charset;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;
public class UnZipAndRarUtil {
private static Logger logger = LoggerFactory.getLogger(UnZipAndRarUtil.class);
private static final int BUFFER_SIZE = 2 * 1024;
/**
* 压缩成ZIP 方法1
*
* @param srcDir 压缩文件夹路径
* @param out 压缩文件输出流
* @param KeepDirStructure 是否保留原来的目录结构,true:保留目录结构;
* false:所有文件跑到压缩包根目录下(注意:不保留目录结构可能会出现同名文件,会压缩失败)
* @throws RuntimeException 压缩失败会抛出运行时异常
*/
public static void toZip(String srcDir, OutputStream out, boolean KeepDirStructure) {
long start = System.currentTimeMillis();
ZipOutputStream zos = null;
try {
zos = new ZipOutputStream(out);
File sourceFile = new File(srcDir);
compress(sourceFile, zos, sourceFile.getName(), KeepDirStructure);
long end = System.currentTimeMillis();
logger.debug("压缩完成,耗时:" + (end - start) + " ms");
} catch (Exception e) {
throw new RuntimeException("zip error from ZipUtils", e);
} finally {
if (zos != null) {
try {
zos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* 压缩成ZIP 方法2
*
* @param srcFiles 需要压缩的文件列表
* @param out 压缩文件输出流
* @throws RuntimeException 压缩失败会抛出运行时异常
*/
public static void toZip(List<File> srcFiles, OutputStream out) {
long start = System.currentTimeMillis();
HashMap<Object, Object> index = new HashMap<>();
int count = 0;
ZipOutputStream zos = null;
try {
zos = new ZipOutputStream(out);
for (File srcFile : srcFiles) {
String fileName = srcFile.getName();
logger.debug("压缩文件名称信息:{}", fileName);
byte[] buf = new byte[BUFFER_SIZE];
//解决文件重名导致压缩失败问题
if (index.containsKey(fileName)) {
count++;
zos.putNextEntry(new ZipEntry("(" + count + ")" + "-" + srcFile.getName()));
index.put("(" + count + ")" + "-" + srcFile.getName(), true);
} else {
zos.putNextEntry(new ZipEntry(srcFile.getName()));
index.put(srcFile.getName(), true);
}
int len;
FileInputStream in = new FileInputStream(srcFile);
while ((len = in.read(buf)) != -1) {
zos.write(buf, 0, len);
}
zos.closeEntry();
in.close();
srcFile.delete();
}
long end = System.currentTimeMillis();
logger.info("压缩完成,耗时:" + (end - start) + " ms");
} catch (Exception e) {
throw new RuntimeException("zip error from ZipUtils", e);
} finally {
if (zos != null) {
try {
zos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* 递归压缩方法
*
* @param sourceFile 源文件
* @param zos zip输出流
* @param name 压缩后的名称
* @param KeepDirStructure 是否保留原来的目录结构,true:保留目录结构;
* false:所有文件跑到压缩包根目录下(注意:不保留目录结构可能会出现同名文件,会压缩失败)
* @throws Exception
*/
private static void compress(File sourceFile, ZipOutputStream zos, String name, boolean KeepDirStructure) {
try {
byte[] buf = new byte[BUFFER_SIZE];
if (sourceFile.isFile()) {
// 向zip输出流中添加一个zip实体,构造器中name为zip实体的文件的名字
zos.putNextEntry(new ZipEntry(name));
// copy文件到zip输出流中
int len;
FileInputStream in = new FileInputStream(sourceFile);
while ((len = in.read(buf)) != -1) {
zos.write(buf, 0, len);
}
zos.closeEntry();
in.close();
} else {
File[] listFiles = sourceFile.listFiles();
if (listFiles == null || listFiles.length == 0) {
// 需要保留原来的文件结构时,需要对空文件夹进行处理
if (KeepDirStructure) {
// 空文件夹的处理
zos.putNextEntry(new ZipEntry(name + "/"));
// 没有文件,不需要文件的copy
zos.closeEntry();
}
} else {
for (File file : listFiles) {
// 判断是否需要保留原来的文件结构
if (KeepDirStructure) {
// 注意:file.getName()前面需要带上父文件夹的名字加一斜杠,
// 不然最后压缩包中就不能保留原来的文件结构,即:所有文件都跑到压缩包根目录下了
compress(file, zos, name + "/" + file.getName(), KeepDirStructure);
} else {
compress(file, zos, file.getName(), KeepDirStructure);
}
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* <功能描述:> 解压文件到指定目录
*
* @param zipFile zip文件
* @param descDir 目标目录
* @param levelDepth 解压的最大层级
* @return void
*/
@SuppressWarnings("rawtypes")
public static int unPackZip(File zipFile, String descDir, int levelDepth) {
int unzipFileNum = 0;
try {
if (!descDir.endsWith("/")) {
descDir = descDir + "/";
}
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();
OutputStream out = null;
try (InputStream in = zip.getInputStream(entry)) {
// 文件名特殊处理
String fileEnd = "";
if (zipEntryName.contains("/")) {
fileEnd = entry.getName().substring(entry.getName().lastIndexOf('/') + 1);
} else {
fileEnd = entry.getName();
}
zipEntryName = zipEntryName.substring(0, zipEntryName.lastIndexOf('/') + 1) + fileEnd;
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;
}
// 获取当前层级
int currentLevel = getCurrentLevel(descDir, outPath);
if (currentLevel <= levelDepth) {
++unzipFileNum;
out = new FileOutputStream(outPath);
byte[] buf1 = new byte[1024];
int len;
while ((len = in.read(buf1)) > 0) {
out.write(buf1, 0, len);
}
//输出文件路径信息
logger.info(String.format("解压ZIP文件= [%s] 中的文件路径[%s]!", zipFile.getName(), outPath));
}
} catch (Exception e) {
logger.error(String.format("解压ZIP文件= [%s] 中的文件出错!", zipFile.getName()), e);
} finally {
if (null != out) {
out.close();
}
}
}
zip.close();
logger.info(String.format("解压[%s]文件,共解压出文件=[%s]个文件!", zipFile.getName(), unzipFileNum));
} catch (IOException e) {
logger.error("解压异常:{}", e);
}
return unzipFileNum;
}
private static int getCurrentLevel(String descDir, String outPath) {
int currentLevel = 0;
String innnerPath = outPath.substring(descDir.length());
String[] folderArray = innnerPath.split("/");
if (null != folderArray && folderArray.length > 1) {
currentLevel = folderArray.length - 1;
}
return currentLevel;
}
public static int unRarFiles(File rarFile, String descDir) {
if (!descDir.endsWith("/")) {
descDir = descDir + "/";
}
File pathFile = new File(descDir);
if (!pathFile.exists()) {
pathFile.mkdirs();
}
try {
// 第一个参数是需要解压的压缩包路径,第二个参数参考JdkAPI文档的RandomAccessFile
//r代表以只读的方式打开文本,也就意味着不能用write来操作文件
RandomAccessFile randomAccessFile = new RandomAccessFile(rarFile.toString(), "r");
// null - autodetect
IInArchive archive = SevenZip.openInArchive(null,
new RandomAccessFileInStream(randomAccessFile));
int[] in = new int[archive.getNumberOfItems()];
for (int i = 0; i < in.length; i++) {
in[i] = i;
}
AtomicInteger fileSum = new AtomicInteger(0);
archive.extract(in, false, new ExtractCallback(archive, pathFile.getAbsolutePath() + "/"));
archive.close();
randomAccessFile.close();
return fileSum.get();
} catch (Exception e) {
logger.error("解压rar出错 {}", e.getMessage());
}
return 0;
}
// public static void main(String[] args) throws Exception {
// String zipFilepath = "D:\\工作内容.zip";
// unPackZip(new File(zipFilepath), null, "D:\\data\\fy\\");
// }
}
3.创建提取文件实现类(IInArchive类属于SevenZip.Archive包)
import net.sf.sevenzipjbinding.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
public class ExtractCallback implements IArchiveExtractCallback {
private static Logger log = LoggerFactory.getLogger(ExtractCallback.class);
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;
String path = (String) inArchive.getProperty(index, PropID.PATH);
final boolean isFolder = (boolean) inArchive.getProperty(index, PropID.IS_FOLDER);
String finalPath = path;
File newfile = null;
try {
String fileEnd = "";
//对文件名,文件夹特殊处理
if (finalPath.contains(File.separator)) {
fileEnd = finalPath.substring(finalPath.lastIndexOf(File.separator) + 1);
} else {
fileEnd = finalPath;
}
finalPath = finalPath.substring(0, finalPath.lastIndexOf(File.separator) + 1) + fileEnd;
//目录层级
finalPath = finalPath.replaceAll("\\\\", "/");
String suffixName = "";
int suffixIndex = fileEnd.lastIndexOf(".");
if (suffixIndex != -1) {
suffixName = fileEnd.substring(suffixIndex + 1);
}
newfile = createFile(isFolder, ourDir + finalPath);
final boolean directory = (boolean) inArchive.getProperty(index, PropID.IS_FOLDER);
} catch (Exception e) {
log.error("rar解压失败{}", e.getMessage());
}
File finalFile = newfile;
return data -> {
save2File(finalFile, data);
return data.length;
};
}
@Override
public void prepareOperation(ExtractAskMode arg0) throws SevenZipException {
}
@Override
public void setOperationResult(ExtractOperationResult extractOperationResult) throws SevenZipException {
}
public static File createFile(boolean isFolder, String path) {
//前置是因为空文件时不会创建文件和文件夹
File file = new File(path);
try {
if (!isFolder) {
File parent = file.getParentFile();
if ((!parent.exists())) {
parent.mkdirs();
}
if (!file.exists()) {
file.createNewFile();
}
} else {
if ((!file.exists())) {
file.mkdirs();
}
}
} catch (Exception e) {
log.error("rar创建文件或文件夹失败 {}", e.getMessage());
}
return file;
}
public static boolean save2File(File file, byte[] msg) {
OutputStream fos = null;
try {
fos = new FileOutputStream(file, true);
fos.write(msg);
fos.flush();
return true;
} catch (FileNotFoundException e) {
log.error("rar保存文件失败{}", e.getMessage());
return false;
} catch (IOException e) {
log.error("rar保存文件失败{}", e.getMessage());
return false;
} finally {
try {
fos.close();
} catch (IOException e) {
log.error("rar保存文件失败{}", e.getMessage());
}
}
}
|