Files
timi-compress/src/main/java/com/imyeyu/compress/Z7Decompressor.java
Timi 829c7f0184
Some checks failed
CI/CD / build-deploy (pull_request) Failing after 10s
v0.0.4
2026-04-07 16:52:13 +08:00

148 lines
3.6 KiB
Java

package com.imyeyu.compress;
import com.imyeyu.io.IO;
import org.apache.commons.compress.archivers.sevenz.SevenZArchiveEntry;
import org.apache.commons.compress.archivers.sevenz.SevenZFile;
import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
/**
* 7z 解压器
*
* @author 夜雨
* @version 2024-06-30 19:42
*/
public class Z7Decompressor extends Decompressor<Z7Decompressor> {
/**
* 创建解压器
*
* @param fromFile 源压缩文件
* @return 解压器
*/
public static Z7Decompressor from(File fromFile) {
return new Z7Decompressor().of(fromFile);
}
/**
* 创建解压器
*
* @param fromPath 源压缩文件路径
* @return 解压器
*/
public static Z7Decompressor from(String fromPath) {
return new Z7Decompressor().of(fromPath);
}
/**
* 创建解压器
*
* @param fromStream 源压缩输入流
* @return 解压器
*/
public static Z7Decompressor from(InputStream fromStream) {
return new Z7Decompressor().of(fromStream);
}
@Override
protected void toPath(File fromFile, String toPath) throws Exception {
initByteProgress(readTotalSize(fromFile));
try {
super.toPath(fromFile, toPath);
} finally {
resetProgress();
}
}
@Override
protected void toPath(InputStream fromStream, String toPath) throws Exception {
Path tempFile = writeTempFile(fromStream);
try (SevenZFile file = SevenZFile.builder().setFile(tempFile.toFile()).get()) {
SevenZArchiveEntry entry;
boolean processed = false;
while ((entry = file.getNextEntry()) != null) {
if (entry.isDirectory()) {
IO.dir(IO.fitPath(toPath) + entry.getName());
} else {
File toFile = IO.file(IO.fitPath(toPath) + entry.getName());
try (OutputStream outputStream = IO.getOutputStream(toFile)) {
copySevenZEntry(file, entry, outputStream);
outputStream.flush();
}
handleFile(toFile);
processed = true;
}
}
if (processed) {
finishProgress();
}
} finally {
Files.deleteIfExists(tempFile);
}
}
/**
* 将输入流写入临时文件
*
* @param fromStream 输入流
* @return 临时文件路径
* @throws Exception 写入失败
*/
private Path writeTempFile(InputStream fromStream) throws Exception {
Path tempFile = Files.createTempFile("timi-compress-", ".7z");
try (OutputStream outputStream = Files.newOutputStream(tempFile)) {
transfer(fromStream, outputStream, false);
outputStream.flush();
}
return tempFile;
}
/**
* 复制当前 7z 条目数据
*
* @param file 7z 文件
* @param entry 当前条目
* @param toStream 输出流
* @throws Exception 复制失败
*/
private void copySevenZEntry(SevenZFile file, SevenZArchiveEntry entry, OutputStream toStream) throws Exception {
byte[] buffer = new byte[8192];
long remain = entry.getSize();
while (0 < remain) {
awaitIfPaused();
ensureRunning();
int length = file.read(buffer, 0, (int) Math.min(buffer.length, remain));
if (length < 0) {
break;
}
toStream.write(buffer, 0, length);
remain -= length;
handleTransferred(length);
}
}
/**
* 读取压缩包解压总字节数
*
* @param fromFile 压缩文件
* @return 总字节数
* @throws Exception 读取失败
*/
private long readTotalSize(File fromFile) throws Exception {
long totalSize = 0L;
try (SevenZFile file = SevenZFile.builder().setFile(fromFile).get()) {
SevenZArchiveEntry entry;
while ((entry = file.getNextEntry()) != null) {
if (!entry.isDirectory()) {
totalSize += entry.getSize();
}
}
}
return totalSize;
}
}