feat CompressUtil 新增 stripComponents 参数 #I67MIK

This commit is contained in:
bwcx_jzy 2022-12-27 18:27:47 +08:00
parent ecde508346
commit b92d98e286
No known key found for this signature in database
GPG Key ID: 5E48E9372088B9E5
4 changed files with 120 additions and 36 deletions

View File

@ -1,10 +1,13 @@
package cn.hutool.extra.compress.extractor; package cn.hutool.extra.compress.extractor;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Filter; import cn.hutool.core.lang.Filter;
import cn.hutool.core.util.StrUtil;
import org.apache.commons.compress.archivers.ArchiveEntry; import org.apache.commons.compress.archivers.ArchiveEntry;
import java.io.Closeable; import java.io.Closeable;
import java.io.File; import java.io.File;
import java.util.List;
/** /**
* 归档数据解包封装用于将ziptar等包解包为文件 * 归档数据解包封装用于将ziptar等包解包为文件
@ -29,7 +32,48 @@ public interface Extractor extends Closeable {
* @param targetDir 目标目录 * @param targetDir 目标目录
* @param filter 解压文件过滤器用于指定需要释放的文件{@code null}表示不过滤{@link Filter#accept(Object)}为true时释放 * @param filter 解压文件过滤器用于指定需要释放的文件{@code null}表示不过滤{@link Filter#accept(Object)}为true时释放
*/ */
void extract(File targetDir, Filter<ArchiveEntry> filter); default void extract(File targetDir, Filter<ArchiveEntry> filter) {
this.extract(targetDir, 0, filter);
}
/**
* 释放解压到指定目录结束后自动关闭流此方法只能调用一次
*
* @param targetDir 目标目录
* @param stripComponents 清除(剥离)压缩包里面的 n 级文件夹名
*/
default void extract(File targetDir, int stripComponents) {
this.extract(targetDir, stripComponents, null);
}
/**
* 释放解压到指定目录结束后自动关闭流此方法只能调用一次
*
* @param targetDir 目标目录
* @param stripComponents 清除(剥离)压缩包里面的 n 级文件夹名
* @param filter 解压文件过滤器用于指定需要释放的文件{@code null}表示不过滤{@link Filter#accept(Object)}为true时释放
*/
void extract(File targetDir, int stripComponents, Filter<ArchiveEntry> filter);
/**
* 剥离名称
*
* @param name 文件名
* @param stripComponents 剥离层级
* @return 剥离后的文件名
*/
default String stripName(String name, int stripComponents) {
if (stripComponents <= 0) {
return name;
}
List<String> nameList = StrUtil.splitTrim(name, StrUtil.SLASH);
int size = nameList.size();
if (size > stripComponents) {
nameList = CollUtil.sub(nameList, stripComponents, size);
return CollUtil.join(nameList, StrUtil.SLASH);
}
return null;
}
/** /**
* 无异常关闭 * 无异常关闭

View File

@ -99,9 +99,9 @@ public class SevenZExtractor implements Extractor, RandomAccess {
* @param filter 解压文件过滤器用于指定需要释放的文件null表示不过滤{@link Filter#accept(Object)}为true时释放 * @param filter 解压文件过滤器用于指定需要释放的文件null表示不过滤{@link Filter#accept(Object)}为true时释放
*/ */
@Override @Override
public void extract(File targetDir, Filter<ArchiveEntry> filter) { public void extract(File targetDir, int stripComponents, Filter<ArchiveEntry> filter) {
try { try {
extractInternal(targetDir, filter); extractInternal(targetDir, stripComponents, filter);
} catch (IOException e) { } catch (IOException e) {
throw new IORuntimeException(e); throw new IORuntimeException(e);
} finally { } finally {
@ -151,10 +151,11 @@ public class SevenZExtractor implements Extractor, RandomAccess {
* 释放解压到指定目录 * 释放解压到指定目录
* *
* @param targetDir 目标目录 * @param targetDir 目标目录
* @param stripComponents 清除(剥离)压缩包里面的 n 级文件夹名
* @param filter 解压文件过滤器用于指定需要释放的文件null表示不过滤{@link Filter#accept(Object)}为true时释放 * @param filter 解压文件过滤器用于指定需要释放的文件null表示不过滤{@link Filter#accept(Object)}为true时释放
* @throws IOException IO异常 * @throws IOException IO异常
*/ */
private void extractInternal(File targetDir, Filter<ArchiveEntry> filter) throws IOException { private void extractInternal(File targetDir, int stripComponents, Filter<ArchiveEntry> filter) throws IOException {
Assert.isTrue(null != targetDir && ((false == targetDir.exists()) || targetDir.isDirectory()), "target must be dir."); Assert.isTrue(null != targetDir && ((false == targetDir.exists()) || targetDir.isDirectory()), "target must be dir.");
final SevenZFile sevenZFile = this.sevenZFile; final SevenZFile sevenZFile = this.sevenZFile;
SevenZArchiveEntry entry; SevenZArchiveEntry entry;
@ -163,7 +164,12 @@ public class SevenZExtractor implements Extractor, RandomAccess {
if (null != filter && false == filter.accept(entry)) { if (null != filter && false == filter.accept(entry)) {
continue; continue;
} }
outItemFile = FileUtil.file(targetDir, entry.getName()); String entryName = this.stripName(entry.getName(), stripComponents);
if (entryName == null) {
// 剥离文件夹层级
continue;
}
outItemFile = FileUtil.file(targetDir, entryName);
if (entry.isDirectory()) { if (entry.isDirectory()) {
// 创建对应目录 // 创建对应目录
//noinspection ResultOfMethodCallIgnored //noinspection ResultOfMethodCallIgnored

View File

@ -104,9 +104,9 @@ public class StreamExtractor implements Extractor{
* @param filter 解压文件过滤器用于指定需要释放的文件null表示不过滤{@link Filter#accept(Object)}为true时释放 * @param filter 解压文件过滤器用于指定需要释放的文件null表示不过滤{@link Filter#accept(Object)}为true时释放
*/ */
@Override @Override
public void extract(File targetDir, Filter<ArchiveEntry> filter) { public void extract(File targetDir, int stripComponents, Filter<ArchiveEntry> filter) {
try { try {
extractInternal(targetDir, filter); extractInternal(targetDir, stripComponents, filter);
} catch (IOException e) { } catch (IOException e) {
throw new IORuntimeException(e); throw new IORuntimeException(e);
} finally { } finally {
@ -118,10 +118,11 @@ public class StreamExtractor implements Extractor{
* 释放解压到指定目录 * 释放解压到指定目录
* *
* @param targetDir 目标目录 * @param targetDir 目标目录
* @param stripComponents 清除(剥离)压缩包里面的 n 级文件夹名
* @param filter 解压文件过滤器用于指定需要释放的文件null表示不过滤{@link Filter#accept(Object)}为true时释放 * @param filter 解压文件过滤器用于指定需要释放的文件null表示不过滤{@link Filter#accept(Object)}为true时释放
* @throws IOException IO异常 * @throws IOException IO异常
*/ */
private void extractInternal(File targetDir, Filter<ArchiveEntry> filter) throws IOException { private void extractInternal(File targetDir, int stripComponents, Filter<ArchiveEntry> filter) throws IOException {
Assert.isTrue(null != targetDir && ((false == targetDir.exists()) || targetDir.isDirectory()), "target must be dir."); Assert.isTrue(null != targetDir && ((false == targetDir.exists()) || targetDir.isDirectory()), "target must be dir.");
final ArchiveInputStream in = this.in; final ArchiveInputStream in = this.in;
ArchiveEntry entry; ArchiveEntry entry;
@ -134,7 +135,12 @@ public class StreamExtractor implements Extractor{
// 无法读取的文件直接跳过 // 无法读取的文件直接跳过
continue; continue;
} }
outItemFile = FileUtil.file(targetDir, entry.getName()); String entryName = this.stripName(entry.getName(), stripComponents);
if (entryName == null) {
// 剥离文件夹层级
continue;
}
outItemFile = FileUtil.file(targetDir, entryName);
if (entry.isDirectory()) { if (entry.isDirectory()) {
// 创建对应目录 // 创建对应目录
//noinspection ResultOfMethodCallIgnored //noinspection ResultOfMethodCallIgnored

View File

@ -6,6 +6,8 @@ import cn.hutool.extra.compress.extractor.Extractor;
import org.junit.Ignore; import org.junit.Ignore;
import org.junit.Test; import org.junit.Test;
import java.io.File;
public class ExtractorTest { public class ExtractorTest {
@Test @Test
@ -38,4 +40,30 @@ public class ExtractorTest {
extractor.extract(FileUtil.file("d:/test/tgz/")); extractor.extract(FileUtil.file("d:/test/tgz/"));
} }
@Test
@Ignore
public void sevenZTest2() {
File targetDir = FileUtil.file("d:/test/sevenZ2/");
FileUtil.clean(targetDir);
//
Extractor extractor = CompressUtil.createExtractor(
CharsetUtil.defaultCharset(),
FileUtil.file("D:/System-Data/Downloads/apache-tomcat-10.0.27.7z"));
extractor.extract(targetDir, 1);
}
@Test
@Ignore
public void zipTest2() {
File targetDir = FileUtil.file("d:/test/zip2/");
FileUtil.clean(targetDir);
//
Extractor extractor = CompressUtil.createExtractor(
CharsetUtil.defaultCharset(),
FileUtil.file("D:/System-Data/Downloads/apache-tomcat-10.0.27.zip"));
extractor.extract(targetDir, 1);
}
} }