This commit is contained in:
Looly 2023-03-22 00:52:52 +08:00
parent 9d350acfb3
commit ea6eb422b3
4 changed files with 61 additions and 24 deletions

View File

@ -1,9 +1,11 @@
package cn.hutool.extra.compress.extractor;
import cn.hutool.core.text.StrUtil;
import org.apache.commons.compress.archivers.ArchiveEntry;
import java.io.Closeable;
import java.io.File;
import java.io.InputStream;
import java.util.function.Predicate;
/**
@ -31,6 +33,24 @@ public interface Extractor extends Closeable {
*/
void extract(File targetDir, Predicate<ArchiveEntry> predicate);
/**
* 获取指定名称的文件流
*
* @param entryName entry名称
* @return 文件流无文件返回{@code null}
*/
default InputStream get(final String entryName) {
return getFirst((entry) -> StrUtil.equals(entryName, entry.getName()));
}
/**
* 获取满足指定过滤要求的压缩包内的第一个文件流
*
* @param predicate 用于指定需要释放的文件null表示不过滤{@link Predicate#test(Object)}{@code true}返回对应流
* @return 满足过滤要求的第一个文件的流, 无满足条件的文件返回{@code null}
*/
InputStream getFirst(final Predicate<ArchiveEntry> predicate);
/**
* 无异常关闭
*/

View File

@ -25,8 +25,18 @@ public class Seven7EntryInputStream extends InputStream {
* @param entry {@link SevenZArchiveEntry}
*/
public Seven7EntryInputStream(final SevenZFile sevenZFile, final SevenZArchiveEntry entry) {
this(sevenZFile, entry.getSize());
}
/**
* 构造
*
* @param sevenZFile {@link SevenZFile}
* @param size 读取长度
*/
public Seven7EntryInputStream(final SevenZFile sevenZFile, final long size) {
this.sevenZFile = sevenZFile;
this.size = entry.getSize();
this.size = size;
}
@Override

View File

@ -1,10 +1,9 @@
package cn.hutool.extra.compress.extractor;
import cn.hutool.core.io.file.FileUtil;
import cn.hutool.core.io.IORuntimeException;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.io.file.FileUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.text.StrUtil;
import org.apache.commons.compress.archivers.ArchiveEntry;
import org.apache.commons.compress.archivers.sevenz.SevenZArchiveEntry;
import org.apache.commons.compress.archivers.sevenz.SevenZFile;
@ -103,13 +102,7 @@ public class SevenZExtractor implements Extractor, RandomAccess {
}
}
/**
* 获取满足指定过滤要求的压缩包内的第一个文件流
*
* @param predicate 用于指定需要释放的文件null表示不过滤{@link Predicate#test(Object)}{@code true}返回对应流
* @return 满足过滤要求的第一个文件的流, 无满足条件的文件返回{@code null}
* @since 5.7.14
*/
@Override
public InputStream getFirst(final Predicate<ArchiveEntry> predicate) {
final SevenZFile sevenZFile = this.sevenZFile;
for (final SevenZArchiveEntry entry : sevenZFile.getEntries()) {
@ -121,6 +114,7 @@ public class SevenZExtractor implements Extractor, RandomAccess {
}
try {
// 此处使用查找entry对应Stream方式由于只调用一次也只遍历一次
return sevenZFile.getInputStream(entry);
} catch (final IOException e) {
throw new IORuntimeException(e);
@ -130,17 +124,6 @@ public class SevenZExtractor implements Extractor, RandomAccess {
return null;
}
/**
* 获取指定名称的文件流
*
* @param entryName entry名称
* @return 文件流无文件返回{@code null}
* @since 5.7.14
*/
public InputStream get(final String entryName) {
return getFirst((entry) -> StrUtil.equals(entryName, entry.getName()));
}
/**
* 释放解压到指定目录
*
@ -153,7 +136,7 @@ public class SevenZExtractor implements Extractor, RandomAccess {
final SevenZFile sevenZFile = this.sevenZFile;
SevenZArchiveEntry entry;
File outItemFile;
while (null != (entry = this.sevenZFile.getNextEntry())) {
while (null != (entry = sevenZFile.getNextEntry())) {
if (null != predicate && false == predicate.test(entry)) {
continue;
}
@ -164,6 +147,7 @@ public class SevenZExtractor implements Extractor, RandomAccess {
outItemFile.mkdirs();
} else if (entry.hasStream()) {
// 读取entry对应数据流
// 此处直接读取而非调用sevenZFile.getInputStream(entry)因为此方法需要遍历查找entry对应位置性能不好
FileUtil.writeFromStream(new Seven7EntryInputStream(sevenZFile, entry), outItemFile);
} else {
// 无数据流的文件创建为空文件

View File

@ -68,7 +68,7 @@ public class StreamExtractor implements Extractor {
* @param in 包流
*/
public StreamExtractor(final Charset charset, final String archiverName, InputStream in) {
if(in instanceof ArchiveInputStream){
if (in instanceof ArchiveInputStream) {
this.in = (ArchiveInputStream) in;
return;
}
@ -78,7 +78,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));
@ -95,6 +95,29 @@ public class StreamExtractor implements Extractor {
}
}
@Override
public InputStream getFirst(final Predicate<ArchiveEntry> predicate) {
final ArchiveInputStream in = this.in;
ArchiveEntry entry;
try {
while (null != (entry = in.getNextEntry())) {
if (null != predicate && false == predicate.test(entry)) {
continue;
}
if (entry.isDirectory() || false == in.canReadEntryData(entry)) {
// 目录或无法读取的文件直接跳过
continue;
}
return in;
}
} catch (final IOException e) {
throw new IORuntimeException(e);
}
return null;
}
/**
* 释放解压到指定目录结束后自动关闭流此方法只能调用一次
*