From b92d98e286dc85a7abc68df55aada1d8c2450855 Mon Sep 17 00:00:00 2001 From: bwcx_jzy Date: Tue, 27 Dec 2022 18:27:47 +0800 Subject: [PATCH] =?UTF-8?q?feat=20CompressUtil=20=E6=96=B0=E5=A2=9E=20stri?= =?UTF-8?q?pComponents=20=E5=8F=82=E6=95=B0=20#I67MIK?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../extra/compress/extractor/Extractor.java | 48 ++++++++++++++++++- .../compress/extractor/SevenZExtractor.java | 40 +++++++++------- .../compress/extractor/StreamExtractor.java | 30 +++++++----- .../hutool/extra/compress/ExtractorTest.java | 38 +++++++++++++-- 4 files changed, 120 insertions(+), 36 deletions(-) diff --git a/hutool-extra/src/main/java/cn/hutool/extra/compress/extractor/Extractor.java b/hutool-extra/src/main/java/cn/hutool/extra/compress/extractor/Extractor.java index ba56e7197..a4b93d4c4 100755 --- a/hutool-extra/src/main/java/cn/hutool/extra/compress/extractor/Extractor.java +++ b/hutool-extra/src/main/java/cn/hutool/extra/compress/extractor/Extractor.java @@ -1,10 +1,13 @@ package cn.hutool.extra.compress.extractor; +import cn.hutool.core.collection.CollUtil; import cn.hutool.core.lang.Filter; +import cn.hutool.core.util.StrUtil; import org.apache.commons.compress.archivers.ArchiveEntry; import java.io.Closeable; import java.io.File; +import java.util.List; /** * 归档数据解包封装,用于将zip、tar等包解包为文件 @@ -19,7 +22,7 @@ public interface Extractor extends Closeable { * * @param targetDir 目标目录 */ - default void extract(File targetDir){ + default void extract(File targetDir) { extract(targetDir, null); } @@ -29,7 +32,48 @@ public interface Extractor extends Closeable { * @param targetDir 目标目录 * @param filter 解压文件过滤器,用于指定需要释放的文件,{@code null}表示不过滤。当{@link Filter#accept(Object)}为true时释放。 */ - void extract(File targetDir, Filter filter); + default void extract(File targetDir, Filter 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 filter); + + /** + * 剥离名称 + * + * @param name 文件名 + * @param stripComponents 剥离层级 + * @return 剥离后的文件名 + */ + default String stripName(String name, int stripComponents) { + if (stripComponents <= 0) { + return name; + } + List 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; + } /** * 无异常关闭 diff --git a/hutool-extra/src/main/java/cn/hutool/extra/compress/extractor/SevenZExtractor.java b/hutool-extra/src/main/java/cn/hutool/extra/compress/extractor/SevenZExtractor.java index f8a769896..68f5b4557 100755 --- a/hutool-extra/src/main/java/cn/hutool/extra/compress/extractor/SevenZExtractor.java +++ b/hutool-extra/src/main/java/cn/hutool/extra/compress/extractor/SevenZExtractor.java @@ -30,7 +30,7 @@ public class SevenZExtractor implements Extractor, RandomAccess { /** * 构造 * - * @param file 包文件 + * @param file 包文件 */ public SevenZExtractor(File file) { this(file, null); @@ -53,7 +53,7 @@ public class SevenZExtractor implements Extractor, RandomAccess { /** * 构造 * - * @param in 包流 + * @param in 包流 */ public SevenZExtractor(InputStream in) { this(in, null); @@ -72,7 +72,7 @@ public class SevenZExtractor implements Extractor, RandomAccess { /** * 构造 * - * @param channel {@link SeekableByteChannel} + * @param channel {@link SeekableByteChannel} */ public SevenZExtractor(SeekableByteChannel channel) { this(channel, null); @@ -99,9 +99,9 @@ public class SevenZExtractor implements Extractor, RandomAccess { * @param filter 解压文件过滤器,用于指定需要释放的文件,null表示不过滤。当{@link Filter#accept(Object)}为true时释放。 */ @Override - public void extract(File targetDir, Filter filter) { + public void extract(File targetDir, int stripComponents, Filter filter) { try { - extractInternal(targetDir, filter); + extractInternal(targetDir, stripComponents, filter); } catch (IOException e) { throw new IORuntimeException(e); } finally { @@ -113,16 +113,16 @@ public class SevenZExtractor implements Extractor, RandomAccess { * 获取满足指定过滤要求的压缩包内的第一个文件流 * * @param filter 用于指定需要释放的文件,null表示不过滤。当{@link Filter#accept(Object)}为true时返回对应流。 - * @return 满足过滤要求的第一个文件的流,无满足条件的文件返回{@code null} + * @return 满足过滤要求的第一个文件的流, 无满足条件的文件返回{@code null} * @since 5.7.14 */ public InputStream getFirst(Filter filter) { final SevenZFile sevenZFile = this.sevenZFile; - for(SevenZArchiveEntry entry : sevenZFile.getEntries()){ - if(null != filter && false == filter.accept(entry)){ + for (SevenZArchiveEntry entry : sevenZFile.getEntries()) { + if (null != filter && false == filter.accept(entry)) { continue; } - if(entry.isDirectory()){ + if (entry.isDirectory()) { continue; } @@ -143,32 +143,38 @@ public class SevenZExtractor implements Extractor, RandomAccess { * @return 文件流,无文件返回{@code null} * @since 5.7.14 */ - public InputStream get(String entryName){ - return getFirst((entry)-> StrUtil.equals(entryName, entry.getName())); + public InputStream get(String entryName) { + return getFirst((entry) -> StrUtil.equals(entryName, entry.getName())); } /** * 释放(解压)到指定目录 * - * @param targetDir 目标目录 - * @param filter 解压文件过滤器,用于指定需要释放的文件,null表示不过滤。当{@link Filter#accept(Object)}为true时释放。 + * @param targetDir 目标目录 + * @param stripComponents 清除(剥离)压缩包里面的 n 级文件夹名 + * @param filter 解压文件过滤器,用于指定需要释放的文件,null表示不过滤。当{@link Filter#accept(Object)}为true时释放。 * @throws IOException IO异常 */ - private void extractInternal(File targetDir, Filter filter) throws IOException { + private void extractInternal(File targetDir, int stripComponents, Filter filter) throws IOException { Assert.isTrue(null != targetDir && ((false == targetDir.exists()) || targetDir.isDirectory()), "target must be dir."); final SevenZFile sevenZFile = this.sevenZFile; SevenZArchiveEntry entry; File outItemFile; while (null != (entry = this.sevenZFile.getNextEntry())) { - if(null != filter && false == filter.accept(entry)){ + if (null != filter && false == filter.accept(entry)) { 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()) { // 创建对应目录 //noinspection ResultOfMethodCallIgnored outItemFile.mkdirs(); - } else if(entry.hasStream()){ + } else if (entry.hasStream()) { // 读取entry对应数据流 FileUtil.writeFromStream(new Seven7EntryInputStream(sevenZFile, entry), outItemFile); } else { diff --git a/hutool-extra/src/main/java/cn/hutool/extra/compress/extractor/StreamExtractor.java b/hutool-extra/src/main/java/cn/hutool/extra/compress/extractor/StreamExtractor.java index 6befe9ad0..f4bd3e8bb 100755 --- a/hutool-extra/src/main/java/cn/hutool/extra/compress/extractor/StreamExtractor.java +++ b/hutool-extra/src/main/java/cn/hutool/extra/compress/extractor/StreamExtractor.java @@ -25,15 +25,15 @@ import java.nio.charset.Charset; * @author looly * @since 5.5.0 */ -public class StreamExtractor implements Extractor{ +public class StreamExtractor implements Extractor { private final ArchiveInputStream in; /** * 构造 * - * @param charset 编码 - * @param file 包文件 + * @param charset 编码 + * @param file 包文件 */ public StreamExtractor(Charset charset, File file) { this(charset, null, file); @@ -70,7 +70,7 @@ public class StreamExtractor implements Extractor{ */ public StreamExtractor(Charset charset, String archiverName, InputStream in) { // issue#2736 自定义ArchiveInputStream - if(in instanceof ArchiveInputStream){ + if (in instanceof ArchiveInputStream) { this.in = (ArchiveInputStream) in; return; } @@ -80,7 +80,7 @@ public class StreamExtractor implements Extractor{ in = IoUtil.toBuffered(in); if (StrUtil.isBlank(archiverName)) { this.in = factory.createArchiveInputStream(in); - } else if("tgz".equalsIgnoreCase(archiverName) || "tar.gz".equalsIgnoreCase(archiverName)){ + } else if ("tgz".equalsIgnoreCase(archiverName) || "tar.gz".equalsIgnoreCase(archiverName)) { //issue#I5J33E,支持tgz格式解压 try { this.in = new TarArchiveInputStream(new GzipCompressorInputStream(in)); @@ -104,9 +104,9 @@ public class StreamExtractor implements Extractor{ * @param filter 解压文件过滤器,用于指定需要释放的文件,null表示不过滤。当{@link Filter#accept(Object)}为true时释放。 */ @Override - public void extract(File targetDir, Filter filter) { + public void extract(File targetDir, int stripComponents, Filter filter) { try { - extractInternal(targetDir, filter); + extractInternal(targetDir, stripComponents, filter); } catch (IOException e) { throw new IORuntimeException(e); } finally { @@ -117,24 +117,30 @@ public class StreamExtractor implements Extractor{ /** * 释放(解压)到指定目录 * - * @param targetDir 目标目录 - * @param filter 解压文件过滤器,用于指定需要释放的文件,null表示不过滤。当{@link Filter#accept(Object)}为true时释放。 + * @param targetDir 目标目录 + * @param stripComponents 清除(剥离)压缩包里面的 n 级文件夹名 + * @param filter 解压文件过滤器,用于指定需要释放的文件,null表示不过滤。当{@link Filter#accept(Object)}为true时释放。 * @throws IOException IO异常 */ - private void extractInternal(File targetDir, Filter filter) throws IOException { + private void extractInternal(File targetDir, int stripComponents, Filter filter) throws IOException { Assert.isTrue(null != targetDir && ((false == targetDir.exists()) || targetDir.isDirectory()), "target must be dir."); final ArchiveInputStream in = this.in; ArchiveEntry entry; File outItemFile; while (null != (entry = in.getNextEntry())) { - if(null != filter && false == filter.accept(entry)){ + if (null != filter && false == filter.accept(entry)) { continue; } if (false == in.canReadEntryData(entry)) { // 无法读取的文件直接跳过 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()) { // 创建对应目录 //noinspection ResultOfMethodCallIgnored diff --git a/hutool-extra/src/test/java/cn/hutool/extra/compress/ExtractorTest.java b/hutool-extra/src/test/java/cn/hutool/extra/compress/ExtractorTest.java index f00febfed..b6f970d41 100644 --- a/hutool-extra/src/test/java/cn/hutool/extra/compress/ExtractorTest.java +++ b/hutool-extra/src/test/java/cn/hutool/extra/compress/ExtractorTest.java @@ -6,11 +6,13 @@ import cn.hutool.extra.compress.extractor.Extractor; import org.junit.Ignore; import org.junit.Test; +import java.io.File; + public class ExtractorTest { @Test @Ignore - public void zipTest(){ + public void zipTest() { Extractor extractor = CompressUtil.createExtractor( CharsetUtil.defaultCharset(), FileUtil.file("d:/test/c_1344112734760931330_20201230104703032.zip")); @@ -20,8 +22,8 @@ public class ExtractorTest { @Test @Ignore - public void sevenZTest(){ - Extractor extractor = CompressUtil.createExtractor( + public void sevenZTest() { + Extractor extractor = CompressUtil.createExtractor( CharsetUtil.defaultCharset(), FileUtil.file("d:/test/compress/test.7z")); @@ -30,12 +32,38 @@ public class ExtractorTest { @Test @Ignore - public void tgzTest(){ - Extractor extractor = CompressUtil.createExtractor( + public void tgzTest() { + Extractor extractor = CompressUtil.createExtractor( CharsetUtil.defaultCharset(), "tgz", FileUtil.file("d:/test/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); + } }