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 { @Override public void run(File fromFile, String toPath) throws Exception { initByteProgress(readTotalSize(fromFile)); try { super.run(fromFile, toPath); } finally { resetProgress(); } } @Override public void run(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; } }