From afcc902cbf7014eb3aaa05a7631d0811d6603e8e Mon Sep 17 00:00:00 2001 From: Timi Date: Wed, 1 Apr 2026 14:09:24 +0800 Subject: [PATCH] v0.0.1 --- .gitea/workflows/ci.yml | 111 ++++++++ .gitignore | 5 +- pom.xml | 76 +++++- .../imyeyu/compress/AbstractCompressor.java | 66 ----- .../com/imyeyu/compress/AbstractRunner.java | 238 ++++++++++++++++++ .../com/imyeyu/compress/CompressType.java | 55 ++-- .../java/com/imyeyu/compress/Compressor.java | 39 ++- .../com/imyeyu/compress/Decompressor.java | 29 ++- .../com/imyeyu/compress/GZipCompressor.java | 60 ++--- .../com/imyeyu/compress/GZipDecompressor.java | 96 ++++--- .../com/imyeyu/compress/TarCompressor.java | 57 ++--- .../com/imyeyu/compress/TarDecompressor.java | 86 ++++--- .../com/imyeyu/compress/Z7Compressor.java | 89 +++++-- .../com/imyeyu/compress/Z7Decompressor.java | 122 ++++++--- .../com/imyeyu/compress/ZipCompressor.java | 57 ++--- .../com/imyeyu/compress/ZipDecompressor.java | 100 +++++--- src/test/java/test/GzipTest.java | 24 +- src/test/java/test/TarTest.java | 24 +- src/test/java/test/Z7Test.java | 24 +- src/test/java/test/ZipTest.java | 24 +- 20 files changed, 986 insertions(+), 396 deletions(-) create mode 100644 .gitea/workflows/ci.yml delete mode 100644 src/main/java/com/imyeyu/compress/AbstractCompressor.java create mode 100644 src/main/java/com/imyeyu/compress/AbstractRunner.java diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml new file mode 100644 index 0000000..c964697 --- /dev/null +++ b/.gitea/workflows/ci.yml @@ -0,0 +1,111 @@ +name: CI/CD + +on: + pull_request: + branches: + - master + types: + - closed + +jobs: + build-deploy: + runs-on: act_runner_java + if: ${{ github.event.pull_request.merged == true }} + env: + JAVA_HOME: /usr/lib/jvm/java-21-openjdk + steps: + - name: Checkout code + run: | + git clone ${{ github.server_url }}/${{ github.repository }}.git . + git checkout ${{ github.sha }} + - name: Set up environment + run: | + echo "PR #${{ github.event.number }} merged into master" + echo "Source branch: ${{ github.event.pull_request.head.ref }}" + echo "Target branch: ${{ github.event.pull_request.base.ref }}" + - name: Run tests + run: | + echo "Running test suite..." + - name: Build project + run: | + mvn -B -DskipTests clean package source:jar javadoc:jar + - name: Deploy to Nexus + if: success() + run: | + if [ -z "${{ secrets.NEXUS_USERNAME }}" ] || [ -z "${{ secrets.NEXUS_PASSWORD }}" ]; then + echo "Missing secrets.NEXUS_USERNAME or secrets.NEXUS_PASSWORD" + exit 1 + fi + mkdir -p ~/.m2 + cat > ~/.m2/settings.xml < + + + timi-nexus + ${{ secrets.NEXUS_USERNAME }} + ${{ secrets.NEXUS_PASSWORD }} + + + + EOF + version=$(mvn -q -DforceStdout help:evaluate -Dexpression=project.version) + artifact_id=$(mvn -q -DforceStdout help:evaluate -Dexpression=project.artifactId) + main_jar="target/${artifact_id}-${version}.jar" + sources_jar="target/${artifact_id}-${version}-sources.jar" + javadoc_jar="target/${artifact_id}-${version}-javadoc.jar" + if [ ! -f "$main_jar" ] || [ ! -f "$sources_jar" ] || [ ! -f "$javadoc_jar" ]; then + echo "Missing build artifacts in target" + exit 1 + fi + mvn -B deploy:deploy-file \ + -Dfile="$main_jar" \ + -Dsources="$sources_jar" \ + -Djavadoc="$javadoc_jar" \ + -DpomFile="./pom.xml" \ + -Durl="https://nexus.imyeyu.com/repository/maven-releases/" \ + -DrepositoryId="timi-nexus" \ + -Dhttps.protocols=TLSv1.2 \ + -Djdk.tls.client.protocols=TLSv1.2 + - name: Create release + if: ${{ success() && startsWith(github.event.pull_request.title, 'v') }} + env: + GITEA_TOKEN: ${{ secrets.RUNNER_TOKEN }} + GITEA_SERVER_URL: ${{ github.server_url }} + GITEA_REPOSITORY: ${{ github.repository }} + RELEASE_TAG: ${{ github.event.pull_request.title }} + RELEASE_TARGET: ${{ github.sha }} + run: | + if [ -z "$GITEA_TOKEN" ]; then + echo "Missing secrets.RUNNER_TOKEN" + exit 1 + fi + api_url="$GITEA_SERVER_URL/api/v1/repos/$GITEA_REPOSITORY/releases" + payload=$(cat < org.apache.maven.plugins - maven-compiler-plugin - 3.11.0 + maven-deploy-plugin + 3.1.4 + + + org.apache.maven.plugins + maven-source-plugin + 3.4.0 + + + org.projectlombok + lombok-maven-plugin + 1.18.20.0 - 21 - 21 + ${project.basedir}/src/main/java + ${project.build.directory}/delombok + false UTF-8 + + + generate-sources + + delombok + + + + + + org.projectlombok + lombok + 1.18.44 + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 3.12.0 + + ${project.build.directory}/delombok + UTF-8 + UTF-8 + UTF-8 + + + + timi_nexus + https://nexus.imyeyu.com/repository/maven-releases/ + + + + + + timi_nexus + https://nexus.imyeyu.com/repository/maven-public/ + + true + + + true + + + + com.imyeyu.io timi-io - 0.0.1 + 0.0.3 org.apache.commons commons-compress - 1.26.1 + 1.28.0 org.tukaani xz - 1.9 + 1.12 + + + org.projectlombok + lombok + 1.18.44 org.junit.jupiter diff --git a/src/main/java/com/imyeyu/compress/AbstractCompressor.java b/src/main/java/com/imyeyu/compress/AbstractCompressor.java deleted file mode 100644 index e592565..0000000 --- a/src/main/java/com/imyeyu/compress/AbstractCompressor.java +++ /dev/null @@ -1,66 +0,0 @@ -package com.imyeyu.compress; - -import com.imyeyu.java.bean.CallbackArg; -import com.imyeyu.utils.OS; - -import java.io.File; - -/** - * 抽象解压缩执行器 - * - * @author 夜雨 - * @since 2024-06-30 18:09 - */ -public abstract class AbstractCompressor implements OS.FileSystem { - - /** 操作文件回调 */ - protected CallbackArg fileCallback; - - /** 进度回调 */ - protected CallbackArg progressCallback; - - /** 中止 */ - protected boolean isInterrupt = false; - - /** 暂停 */ - protected boolean isPause = false; - - /** 暂停锁 */ - protected final Object pauseLock = new Object(); - - /** 暂停 */ - public void pause() { - isPause = true; - } - - /** 开始 */ - public void start() { - isPause = false; - synchronized (pauseLock) { - pauseLock.notifyAll(); - } - } - - /** 中止 */ - public void interrupt() { - isInterrupt = true; - } - - /** - * 设置操作文件回调。正在压缩或解压某文件时触发 - * - * @param fileCallback 回调接口 - */ - public void setFileCallback(CallbackArg fileCallback) { - this.fileCallback = fileCallback; - } - - /** - * 设置进度回调 - * - * @param progressCallback 回调接口 - */ - public void setProgressCallback(CallbackArg progressCallback) { - this.progressCallback = progressCallback; - } -} diff --git a/src/main/java/com/imyeyu/compress/AbstractRunner.java b/src/main/java/com/imyeyu/compress/AbstractRunner.java new file mode 100644 index 0000000..da93009 --- /dev/null +++ b/src/main/java/com/imyeyu/compress/AbstractRunner.java @@ -0,0 +1,238 @@ +package com.imyeyu.compress; + +import com.imyeyu.java.bean.CallbackArg; +import com.imyeyu.utils.OS; +import lombok.Setter; + +import java.io.File; +import java.io.FilterInputStream; +import java.io.FilterOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +/** + * 抽象压缩执行器 + * + * @author 夜雨 + * @since 2024-06-30 18:09 + */ +public abstract class AbstractRunner implements OS.FileSystem { + + /** 文件处理回调 */ + @Setter + protected CallbackArg fileCallback; + + /** 进度回调 */ + @Setter + protected CallbackArg progressCallback; + + /** 中断标记 */ + protected boolean isInterrupt = false; + + /** 暂停标记 */ + protected boolean isPause = false; + + /** 暂停锁 */ + protected final Object pauseLock = new Object(); + + /** 总字节数 */ + private long progressTotalBytes = -1L; + + /** 当前已处理字节数 */ + private long progressBytes = 0L; + + /** 暂停任务 */ + public void pause() { + isPause = true; + } + + /** 恢复任务 */ + public void start() { + isPause = false; + synchronized (pauseLock) { + pauseLock.notifyAll(); + } + } + + /** 中断任务 */ + public void interrupt() { + isInterrupt = true; + } + + /** + * 初始化字节进度 + * + * @param totalBytes 总字节数 + */ + protected void initByteProgress(long totalBytes) { + progressBytes = 0L; + progressTotalBytes = totalBytes; + } + + /** 重置进度状态 */ + protected void resetProgress() { + progressBytes = 0L; + progressTotalBytes = -1L; + } + + /** + * 执行暂停检查 + * + * @throws InterruptedException 等待恢复时被中断 + */ + protected void awaitIfPaused() throws InterruptedException { + if (!isPause) { + return; + } + synchronized (pauseLock) { + while (isPause) { + pauseLock.wait(); + } + } + } + + /** + * 检查是否已经中断 + * + * @throws IOException 操作已中断 + */ + protected void ensureRunning() throws IOException { + if (isInterrupt) { + throw new IOException("操作已中断"); + } + } + + /** + * 触发文件回调 + * + * @param file 当前处理的文件 + */ + protected void handleFile(File file) { + if (fileCallback != null) { + fileCallback.handler(file); + } + } + + /** + * 触发进度回调 + * + * @param currentBytes 当前已处理字节数 + * @param totalBytes 总字节数 + */ + protected void handleProgress(long currentBytes, long totalBytes) { + if (progressCallback == null || totalBytes < 1L) { + return; + } + double progress = Math.min(1D, currentBytes * 1D / totalBytes); + progressCallback.handler(progress); + } + + /** + * 增加已处理字节数并回调 + * + * @param bytes 本次新增字节数 + */ + protected void handleTransferred(long bytes) { + if (bytes < 1L) { + return; + } + progressBytes += bytes; + handleProgress(progressBytes, progressTotalBytes); + } + + /** 将进度推进到完成态 */ + protected void finishProgress() { + if (progressCallback != null) { + progressCallback.handler(1D); + } + } + + /** + * 复制数据流并更新进度 + * + * @param fromStream 输入流 + * @param toStream 输出流 + * @return 已复制字节数 + * @throws Exception 复制失败 + */ + protected long transfer(InputStream fromStream, OutputStream toStream) throws Exception { + return transfer(fromStream, toStream, true); + } + + /** + * 复制数据流 + * + * @param fromStream 输入流 + * @param toStream 输出流 + * @param countProgress 是否统计进度 + * @return 已复制字节数 + * @throws Exception 复制失败 + */ + protected long transfer(InputStream fromStream, OutputStream toStream, boolean countProgress) throws Exception { + byte[] buffer = new byte[8192]; + long total = 0L; + int length; + while ((length = fromStream.read(buffer)) != -1) { + awaitIfPaused(); + ensureRunning(); + toStream.write(buffer, 0, length); + total += length; + if (countProgress) { + handleTransferred(length); + } + } + return total; + } + + /** + * 创建一个关闭时不关闭原始流的输入流包装 + * + * @param inputStream 原始输入流 + * @return 包装后的输入流 + */ + protected InputStream nonClosing(InputStream inputStream) { + return new FilterInputStream(inputStream) { + + @Override + public void close() { + } + }; + } + + /** + * 创建一个关闭时不关闭原始流的输出流包装 + * + * @param outputStream 原始输出流 + * @return 包装后的输出流 + */ + protected OutputStream nonClosing(OutputStream outputStream) { + return new FilterOutputStream(outputStream) { + + @Override + public void close() throws IOException { + flush(); + } + }; + } + + /** + * 规范化归档条目名称 + * + * @param entryName 条目名称 + * @return 规范化后的名称 + */ + protected String normalizeEntryName(String entryName) { + if (entryName == null || entryName.isBlank()) { + throw new IllegalArgumentException("条目名称不能为空"); + } + String normalized = entryName.replace('\\', '/'); + while (normalized.startsWith("/")) { + normalized = normalized.substring(1); + } + if (normalized.isBlank()) { + throw new IllegalArgumentException("条目名称不能为空"); + } + return normalized; + } +} diff --git a/src/main/java/com/imyeyu/compress/CompressType.java b/src/main/java/com/imyeyu/compress/CompressType.java index db27f55..3566741 100644 --- a/src/main/java/com/imyeyu/compress/CompressType.java +++ b/src/main/java/com/imyeyu/compress/CompressType.java @@ -2,6 +2,10 @@ package com.imyeyu.compress; import com.imyeyu.io.IO; import com.imyeyu.java.ref.Ref; +import org.apache.commons.compress.archivers.sevenz.SevenZFile; +import org.apache.commons.compress.archivers.tar.TarArchiveInputStream; +import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream; +import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream; import java.io.File; import java.io.InputStream; @@ -15,16 +19,16 @@ import java.io.InputStream; public enum CompressType { /** 7z */ - Z7(Z7Compressor.class, Z7Decompressor.class, -0x51), + Z7(Z7Compressor.class, Z7Decompressor.class), /** Zip */ - ZIP(ZipCompressor.class, ZipDecompressor.class, 0x504B0304), + ZIP(ZipCompressor.class, ZipDecompressor.class), /** Gzip */ - GZIP(GZipCompressor.class, GZipDecompressor.class, -0x74F7F8), + GZIP(GZipCompressor.class, GZipDecompressor.class), - /** tar */ - TAR(TarCompressor.class, TarDecompressor.class, 0x776F7264); + /** Tar */ + TAR(TarCompressor.class, TarDecompressor.class); /** 压缩类 */ final Class compressorType; @@ -32,13 +36,9 @@ public enum CompressType { /** 解压类 */ final Class decompressorType; - /** 文件头标记 */ - final int headHex; - - CompressType(Class compressorType, Class decompressorType, int headHex) { + CompressType(Class compressorType, Class decompressorType) { this.compressorType = compressorType; this.decompressorType = decompressorType; - this.headHex = headHex; } /** @@ -62,28 +62,31 @@ public enum CompressType { } /** - * 根据文件获取解压操作对象。将会读取文件头解析算法类型 + * 根据文件获取解压操作对象。会读取文件头识别压缩格式 * * @param file 文件 * @return 解压操作对象 * @throws UnsupportedOperationException 不支持的文件 - * @throws Exception 实例化失败 + * @throws Exception 实例化失败 */ public static Decompressor fromFile(File file) throws Exception { - InputStream is = IO.getInputStream(file); - byte[] head = new byte[4]; - if (-1 == is.read(head)) { - throw new UnsupportedOperationException("not support file"); - } - is.close(); - int headHex = 0; - for (byte b : head) { - headHex <<= 8; - headHex |= b; - } - for (CompressType type : values()) { - if (type.headHex == headHex) { - return type.getDecompressor(); + try (InputStream inputStream = IO.getInputStream(file)) { + byte[] head = new byte[512]; + int length = inputStream.read(head); + if (length == -1) { + throw new UnsupportedOperationException("not support file"); + } + if (SevenZFile.matches(head, length)) { + return Z7.getDecompressor(); + } + if (ZipArchiveInputStream.matches(head, length)) { + return ZIP.getDecompressor(); + } + if (GzipCompressorInputStream.matches(head, length)) { + return GZIP.getDecompressor(); + } + if (TarArchiveInputStream.matches(head, length)) { + return TAR.getDecompressor(); } } throw new UnsupportedOperationException("not support headHex"); diff --git a/src/main/java/com/imyeyu/compress/Compressor.java b/src/main/java/com/imyeyu/compress/Compressor.java index 0191c91..c92894a 100644 --- a/src/main/java/com/imyeyu/compress/Compressor.java +++ b/src/main/java/com/imyeyu/compress/Compressor.java @@ -1,14 +1,47 @@ package com.imyeyu.compress; +import com.imyeyu.io.IO; + import java.io.File; +import java.io.OutputStream; /** - * + * 抽象压缩器 * * @author 夜雨 * @version 2024-06-30 10:34 */ -public abstract class Compressor extends AbstractCompressor { +public abstract class Compressor extends AbstractRunner { - public abstract void run(String fromPath, File toFile) throws Exception; + /** + * 将指定路径下的文件压缩到目标文件 + * + * @param fromPath 源路径 + * @param toFile 目标压缩文件 + * @throws Exception 压缩失败 + */ + public void run(String fromPath, File toFile) throws Exception { + try (OutputStream outputStream = IO.getOutputStream(toFile)) { + run(fromPath, outputStream); + outputStream.flush(); + } catch (Exception exception) { + if (isInterrupt) { + IO.destroy(toFile); + } + throw exception; + } + if (isInterrupt) { + IO.destroy(toFile); + } + } + + /** + * 将指定路径下的文件压缩到输出流 + * 输出流由调用方管理 + * + * @param fromPath 源路径 + * @param toStream 目标输出流 + * @throws Exception 压缩失败 + */ + public abstract void run(String fromPath, OutputStream toStream) throws Exception; } diff --git a/src/main/java/com/imyeyu/compress/Decompressor.java b/src/main/java/com/imyeyu/compress/Decompressor.java index e21dbbc..dc5b9b2 100644 --- a/src/main/java/com/imyeyu/compress/Decompressor.java +++ b/src/main/java/com/imyeyu/compress/Decompressor.java @@ -1,21 +1,38 @@ package com.imyeyu.compress; +import com.imyeyu.io.IO; + import java.io.File; +import java.io.InputStream; /** - * 抽象解压 + * 抽象解压器 * * @author 夜雨 * @version 2024-06-30 18:02 */ -public abstract class Decompressor extends AbstractCompressor { +public abstract class Decompressor extends AbstractRunner { /** - * 执行解压 + * 将压缩文件解压到目标目录 * - * @param fromFile 来源压缩文件 - * @param toPath 解压路径 + * @param fromFile 源压缩文件 + * @param toPath 目标目录 * @throws Exception 解压失败 */ - public abstract void run(File fromFile, String toPath) throws Exception; + public void run(File fromFile, String toPath) throws Exception { + try (InputStream inputStream = IO.getInputStream(fromFile)) { + run(inputStream, toPath); + } + } + + /** + * 将压缩输入流解压到目标目录 + * 输入流由调用方管理 + * + * @param fromStream 源压缩输入流 + * @param toPath 目标目录 + * @throws Exception 解压失败 + */ + public abstract void run(InputStream fromStream, String toPath) throws Exception; } diff --git a/src/main/java/com/imyeyu/compress/GZipCompressor.java b/src/main/java/com/imyeyu/compress/GZipCompressor.java index e3531cc..6a662c2 100644 --- a/src/main/java/com/imyeyu/compress/GZipCompressor.java +++ b/src/main/java/com/imyeyu/compress/GZipCompressor.java @@ -7,54 +7,44 @@ import org.apache.commons.compress.compressors.gzip.GzipCompressorOutputStream; import java.io.BufferedOutputStream; import java.io.File; +import java.io.InputStream; import java.io.OutputStream; import java.util.List; /** + * Gzip 压缩器 + * 当前实现保持与原行为一致,实际输出为 tar.gz + * * @author 夜雨 * @version 2024-06-30 19:40 */ public class GZipCompressor extends Compressor { @Override - public void run(String fromPath, File toFile) throws Exception { - List files = IO.listFile(new File(fromPath)); + public void run(String fromPath, OutputStream toStream) throws Exception { + File fromFile = new File(fromPath); + List files = IO.listFile(fromFile); String basePath = files.getFirst().getParentFile().getAbsolutePath(); - - OutputStream os = IO.getOutputStream(toFile); - BufferedOutputStream byteOS = new BufferedOutputStream(os); - GzipCompressorOutputStream gzipOS = new GzipCompressorOutputStream(byteOS); - TarArchiveOutputStream tarOS = new TarArchiveOutputStream(gzipOS); - - TarArchiveEntry tarEntry; - for (int i = 0, total = files.size(); i < total; i++) { - String name = files.get(i).getAbsolutePath().substring(basePath.length() + 1); - tarEntry = new TarArchiveEntry(files.get(i), name.replaceAll("\\\\", "/")); - tarOS.putArchiveEntry(tarEntry); - tarOS.write(IO.toBytes(files.get(i))); - tarOS.closeArchiveEntry(); - - if (isPause) { - synchronized (pauseLock) { - pauseLock.wait(); + initByteProgress(IO.calcSize(fromFile)); + try ( + GzipCompressorOutputStream gzipOutputStream = new GzipCompressorOutputStream(new BufferedOutputStream(nonClosing(toStream))); + TarArchiveOutputStream tarOutputStream = new TarArchiveOutputStream(gzipOutputStream) + ) { + for (File sourceFile : files) { + String name = sourceFile.getAbsolutePath().substring(basePath.length() + 1); + TarArchiveEntry tarEntry = new TarArchiveEntry(sourceFile, normalizeEntryName(name)); + tarOutputStream.putArchiveEntry(tarEntry); + try (InputStream inputStream = IO.getInputStream(sourceFile)) { + transfer(inputStream, tarOutputStream); } + tarOutputStream.closeArchiveEntry(); + handleFile(sourceFile); } - if (fileCallback != null) { - fileCallback.handler(toFile); - } - if (progressCallback != null) { - progressCallback.handler(1D * i / total); - } - if (isInterrupt) { - break; - } + tarOutputStream.finish(); + gzipOutputStream.finish(); + finishProgress(); + } finally { + resetProgress(); } - tarOS.finish(); - tarOS.close(); - gzipOS.finish(); - gzipOS.close(); - byteOS.flush(); - byteOS.close(); - os.close(); } } diff --git a/src/main/java/com/imyeyu/compress/GZipDecompressor.java b/src/main/java/com/imyeyu/compress/GZipDecompressor.java index 09e7632..327d83c 100644 --- a/src/main/java/com/imyeyu/compress/GZipDecompressor.java +++ b/src/main/java/com/imyeyu/compress/GZipDecompressor.java @@ -7,8 +7,12 @@ import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream; import java.io.File; import java.io.InputStream; +import java.io.OutputStream; /** + * Gzip 解压器 + * 当前实现保持与原行为一致,实际按 tar.gz 解压 + * * @author 夜雨 * @version 2024-06-30 19:47 */ @@ -16,51 +20,63 @@ public class GZipDecompressor extends Decompressor { @Override public void run(File fromFile, String toPath) throws Exception { - InputStream is = IO.getInputStream(fromFile); - GzipCompressorInputStream gzipIS = new GzipCompressorInputStream(is); - TarArchiveInputStream tarIS = new TarArchiveInputStream(gzipIS); + initByteProgress(readTotalSize(fromFile)); + try { + super.run(fromFile, toPath); + } finally { + resetProgress(); + } + } - int total = 0; - { + @Override + public void run(InputStream fromStream, String toPath) throws Exception { + try ( + GzipCompressorInputStream gzipInputStream = new GzipCompressorInputStream(nonClosing(fromStream)); + TarArchiveInputStream tarInputStream = new TarArchiveInputStream(gzipInputStream) + ) { TarArchiveEntry entry; - while ((entry = tarIS.getNextEntry()) != null) { + boolean processed = false; + while ((entry = tarInputStream.getNextEntry()) != null) { + String path = IO.fitPath(toPath) + entry.getName(); + if (entry.isDirectory()) { + IO.dir(path); + } else { + File toFile = IO.file(path); + try (OutputStream outputStream = IO.getOutputStream(toFile)) { + transfer(tarInputStream, outputStream); + outputStream.flush(); + } + handleFile(toFile); + processed = true; + } + } + if (processed) { + finishProgress(); + } + } + } + + /** + * 读取压缩包解压总字节数 + * + * @param fromFile 压缩文件 + * @return 总字节数 + * @throws Exception 读取失败 + */ + private long readTotalSize(File fromFile) throws Exception { + long totalSize = 0L; + try ( + InputStream inputStream = IO.getInputStream(fromFile); + GzipCompressorInputStream gzipInputStream = new GzipCompressorInputStream(inputStream); + TarArchiveInputStream tarInputStream = new TarArchiveInputStream(gzipInputStream) + ) { + TarArchiveEntry entry; + while ((entry = tarInputStream.getNextEntry()) != null) { if (!entry.isDirectory()) { - total++; + totalSize += entry.getSize(); } } } - tarIS.close(); - is.close(); - - is = IO.getInputStream(fromFile); - tarIS = new TarArchiveInputStream(is); - TarArchiveEntry entry; - for (int i = 0; (entry = tarIS.getNextEntry()) != null; i++) { - String path = IO.fitPath(toPath) + entry.getName(); - if (entry.isDirectory()) { - IO.dir(path); - } else { - File toFile = IO.file(path); - IO.toFile(toFile, tarIS); - - if (fileCallback != null) { - fileCallback.handler(toFile); - } - } - if (isPause) { - synchronized (pauseLock) { - pauseLock.wait(); - } - } - if (progressCallback != null && total != -1) { - progressCallback.handler(1D * i / total); - } - if (isInterrupt) { - break; - } - } - tarIS.close(); - gzipIS.close(); - is.close(); + return totalSize; } } diff --git a/src/main/java/com/imyeyu/compress/TarCompressor.java b/src/main/java/com/imyeyu/compress/TarCompressor.java index ed0d631..505abf7 100644 --- a/src/main/java/com/imyeyu/compress/TarCompressor.java +++ b/src/main/java/com/imyeyu/compress/TarCompressor.java @@ -6,56 +6,39 @@ import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream; import java.io.BufferedOutputStream; import java.io.File; +import java.io.InputStream; import java.io.OutputStream; import java.util.List; /** + * Tar 压缩器 + * * @author 夜雨 * @version 2024-06-30 19:48 */ public class TarCompressor extends Compressor { @Override - public void run(String fromPath, File toFile) throws Exception { - List files = IO.listFile(new File(fromPath)); + public void run(String fromPath, OutputStream toStream) throws Exception { + File fromFile = new File(fromPath); + List files = IO.listFile(fromFile); String basePath = files.getFirst().getParentFile().getAbsolutePath(); - - OutputStream os = IO.getOutputStream(toFile); - BufferedOutputStream byteOS = new BufferedOutputStream(os); - TarArchiveOutputStream tarOS = new TarArchiveOutputStream(byteOS); - - TarArchiveEntry tarEntry; - for (int i = 0, total = files.size(); i < total; i++) { - String name = files.get(i).getAbsolutePath().substring(basePath.length() + 1); - tarEntry = new TarArchiveEntry(files.get(i), name.replaceAll("\\\\", "/")); - tarOS.putArchiveEntry(tarEntry); - tarOS.write(IO.toBytes(files.get(i))); - tarOS.closeArchiveEntry(); - - if (isPause) { - synchronized (pauseLock) { - pauseLock.wait(); + initByteProgress(IO.calcSize(fromFile)); + try (TarArchiveOutputStream tarOutputStream = new TarArchiveOutputStream(new BufferedOutputStream(nonClosing(toStream)))) { + for (File sourceFile : files) { + String name = sourceFile.getAbsolutePath().substring(basePath.length() + 1); + TarArchiveEntry tarEntry = new TarArchiveEntry(sourceFile, normalizeEntryName(name)); + tarOutputStream.putArchiveEntry(tarEntry); + try (InputStream inputStream = IO.getInputStream(sourceFile)) { + transfer(inputStream, tarOutputStream); } + tarOutputStream.closeArchiveEntry(); + handleFile(sourceFile); } - if (fileCallback != null) { - fileCallback.handler(toFile); - } - if (progressCallback != null) { - progressCallback.handler(1D * i / total); - } - if (isInterrupt) { - break; - } - } - tarOS.finish(); - tarOS.close(); - byteOS.flush(); - byteOS.close(); - os.flush(); - os.close(); - - if (isInterrupt) { - IO.destroy(toFile); + tarOutputStream.finish(); + finishProgress(); + } finally { + resetProgress(); } } } diff --git a/src/main/java/com/imyeyu/compress/TarDecompressor.java b/src/main/java/com/imyeyu/compress/TarDecompressor.java index e893224..4f2e31c 100644 --- a/src/main/java/com/imyeyu/compress/TarDecompressor.java +++ b/src/main/java/com/imyeyu/compress/TarDecompressor.java @@ -6,8 +6,11 @@ import org.apache.commons.compress.archivers.tar.TarArchiveInputStream; import java.io.File; import java.io.InputStream; +import java.io.OutputStream; /** + * Tar 解压器 + * * @author 夜雨 * @version 2024-06-30 19:48 */ @@ -15,49 +18,56 @@ public class TarDecompressor extends Decompressor { @Override public void run(File fromFile, String toPath) throws Exception { - InputStream is = IO.getInputStream(fromFile); - TarArchiveInputStream tarIS = new TarArchiveInputStream(is); + initByteProgress(readTotalSize(fromFile)); + try { + super.run(fromFile, toPath); + } finally { + resetProgress(); + } + } - int total = 0; - { + @Override + public void run(InputStream fromStream, String toPath) throws Exception { + try (TarArchiveInputStream tarInputStream = new TarArchiveInputStream(nonClosing(fromStream))) { TarArchiveEntry entry; - while ((entry = tarIS.getNextEntry()) != null) { + boolean processed = false; + while ((entry = tarInputStream.getNextEntry()) != null) { + String path = IO.fitPath(toPath) + entry.getName(); + if (entry.isDirectory()) { + IO.dir(path); + } else { + File toFile = IO.file(path); + try (OutputStream outputStream = IO.getOutputStream(toFile)) { + transfer(tarInputStream, outputStream); + outputStream.flush(); + } + handleFile(toFile); + processed = true; + } + } + if (processed) { + finishProgress(); + } + } + } + + /** + * 读取压缩包解压总字节数 + * + * @param fromFile 压缩文件 + * @return 总字节数 + * @throws Exception 读取失败 + */ + private long readTotalSize(File fromFile) throws Exception { + long totalSize = 0L; + try (InputStream inputStream = IO.getInputStream(fromFile); TarArchiveInputStream tarInputStream = new TarArchiveInputStream(inputStream)) { + TarArchiveEntry entry; + while ((entry = tarInputStream.getNextEntry()) != null) { if (!entry.isDirectory()) { - total++; + totalSize += entry.getSize(); } } } - tarIS.close(); - is.close(); - - is = IO.getInputStream(fromFile); - tarIS = new TarArchiveInputStream(is); - TarArchiveEntry entry; - for (int i = 0; (entry = tarIS.getNextEntry()) != null; i++) { - String path = IO.fitPath(toPath) + entry.getName(); - if (entry.isDirectory()) { - IO.dir(path); - } else { - File toFile = IO.file(path); - IO.toFile(toFile, tarIS); - - if (fileCallback != null) { - fileCallback.handler(toFile); - } - } - if (isPause) { - synchronized (pauseLock) { - pauseLock.wait(); - } - } - if (progressCallback != null && total != -1) { - progressCallback.handler(1D * i / total); - } - if (isInterrupt) { - break; - } - } - tarIS.close(); - is.close(); + return totalSize; } } diff --git a/src/main/java/com/imyeyu/compress/Z7Compressor.java b/src/main/java/com/imyeyu/compress/Z7Compressor.java index 943ffb9..23f1f8b 100644 --- a/src/main/java/com/imyeyu/compress/Z7Compressor.java +++ b/src/main/java/com/imyeyu/compress/Z7Compressor.java @@ -5,46 +5,81 @@ import org.apache.commons.compress.archivers.sevenz.SevenZArchiveEntry; import org.apache.commons.compress.archivers.sevenz.SevenZOutputFile; import java.io.File; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.List; /** + * 7z 压缩器 + * * @author 夜雨 * @version 2024-06-30 19:40 */ public class Z7Compressor extends Compressor { @Override - public void run(String fromPath, File toFile) throws Exception { - List files = IO.listFile(new File(fromPath)); - String basePath = files.getFirst().getParentFile().getAbsolutePath(); - - SevenZOutputFile out = new SevenZOutputFile(toFile); - SevenZArchiveEntry entry; - for (int i = 0, total = files.size(); i < total; i++) { - String name = files.get(i).getAbsolutePath().substring(basePath.length() + 1); - entry = out.createArchiveEntry(files.get(i), name.replaceAll("\\\\", "/")); - out.putArchiveEntry(entry); - out.write(IO.toBytes(files.get(i))); - out.closeArchiveEntry(); - - if (isPause) { - synchronized (pauseLock) { - pauseLock.wait(); - } - } - if (fileCallback != null) { - fileCallback.handler(toFile); - } - if (progressCallback != null) { - progressCallback.handler(1D * i / total); - } - if (isInterrupt) { - break; + public void run(String fromPath, OutputStream toStream) throws Exception { + Path tempFile = Files.createTempFile("timi-compress-", ".7z"); + try { + run(fromPath, tempFile.toFile()); + try (InputStream inputStream = Files.newInputStream(tempFile)) { + transfer(inputStream, toStream, false); + toStream.flush(); } + } finally { + Files.deleteIfExists(tempFile); + } + } + + @Override + public void run(String fromPath, File toFile) throws Exception { + File fromFile = new File(fromPath); + List files = IO.listFile(fromFile); + String basePath = files.getFirst().getParentFile().getAbsolutePath(); + initByteProgress(IO.calcSize(fromFile)); + try (SevenZOutputFile outputFile = new SevenZOutputFile(toFile)) { + for (File sourceFile : files) { + String name = sourceFile.getAbsolutePath().substring(basePath.length() + 1); + SevenZArchiveEntry entry = outputFile.createArchiveEntry(sourceFile, normalizeEntryName(name)); + outputFile.putArchiveEntry(entry); + writeSevenZEntry(outputFile, sourceFile); + outputFile.closeArchiveEntry(); + handleFile(sourceFile); + } + outputFile.finish(); + finishProgress(); + } catch (Exception exception) { + if (isInterrupt) { + IO.destroy(toFile); + } + throw exception; + } finally { + resetProgress(); } - out.close(); if (isInterrupt) { IO.destroy(toFile); } } + + /** + * 写入 7z 条目内容 + * + * @param outputFile 7z 输出文件 + * @param sourceFile 源文件 + * @throws Exception 写入失败 + */ + private void writeSevenZEntry(SevenZOutputFile outputFile, File sourceFile) throws Exception { + byte[] buffer = new byte[8192]; + try (InputStream inputStream = IO.getInputStream(sourceFile)) { + int length; + while ((length = inputStream.read(buffer)) != -1) { + awaitIfPaused(); + ensureRunning(); + outputFile.write(buffer, 0, length); + handleTransferred(length); + } + } + } } diff --git a/src/main/java/com/imyeyu/compress/Z7Decompressor.java b/src/main/java/com/imyeyu/compress/Z7Decompressor.java index c65e73e..473fd3b 100644 --- a/src/main/java/com/imyeyu/compress/Z7Decompressor.java +++ b/src/main/java/com/imyeyu/compress/Z7Decompressor.java @@ -5,8 +5,14 @@ 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 */ @@ -14,44 +20,98 @@ public class Z7Decompressor extends Decompressor { @Override public void run(File fromFile, String toPath) throws Exception { - toPath = new File(toPath).getAbsolutePath() + SEP; - - int total = 0; - if (progressCallback != null) { - SevenZFile file = SevenZFile.builder().setFile(fromFile).get(); - try (file) { - while (file.getNextEntry() != null) { - total++; - } - } + initByteProgress(readTotalSize(fromFile)); + try { + super.run(fromFile, toPath); + } finally { + resetProgress(); } - SevenZFile file = SevenZFile.builder().setFile(fromFile).get(); - SevenZArchiveEntry entry; - for (int i = 0; (entry = file.getNextEntry()) != null; i++) { - if (entry.isDirectory()) { - IO.dir(IO.fitPath(toPath) + entry.getName()); - } else { - File toFile = IO.file(toPath + entry.getName()); - byte[] buffer = new byte[(int) entry.getSize()]; - file.read(buffer, 0, buffer.length); - IO.toFile(toFile, buffer); + } - if (fileCallback != null) { - fileCallback.handler(toFile); + @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 (isPause) { - synchronized (pauseLock) { - pauseLock.wait(); - } + if (processed) { + finishProgress(); } - if (progressCallback != null && total != -1) { - progressCallback.handler(1D * i / total); - } - if (isInterrupt) { + } 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); } - file.close(); + } + + /** + * 读取压缩包解压总字节数 + * + * @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; } } diff --git a/src/main/java/com/imyeyu/compress/ZipCompressor.java b/src/main/java/com/imyeyu/compress/ZipCompressor.java index 2d384ba..e82d897 100644 --- a/src/main/java/com/imyeyu/compress/ZipCompressor.java +++ b/src/main/java/com/imyeyu/compress/ZipCompressor.java @@ -4,57 +4,40 @@ import com.imyeyu.io.IO; import java.io.BufferedOutputStream; import java.io.File; +import java.io.InputStream; import java.io.OutputStream; import java.util.List; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; /** + * Zip 压缩器 + * * @author 夜雨 * @version 2024-06-30 19:46 */ public class ZipCompressor extends Compressor { @Override - public void run(String fromPath, File toFile) throws Exception { - List files = IO.listFile(new File(fromPath)); + public void run(String fromPath, OutputStream toStream) throws Exception { + File fromFile = new File(fromPath); + List files = IO.listFile(fromFile); String basePath = files.getFirst().getParentFile().getAbsolutePath(); - - OutputStream os = IO.getOutputStream(toFile); - BufferedOutputStream byteOS = new BufferedOutputStream(os); - ZipOutputStream zipOS = new ZipOutputStream(byteOS); - - for (int i = 0, total = files.size(); i < total; i++) { - String name = files.get(i).getAbsolutePath().substring(basePath.length() + 1); - ZipEntry zipEntry = new ZipEntry(name.replaceAll("\\\\", "/")); - zipOS.putNextEntry(zipEntry); - zipOS.write(IO.toBytes(files.get(i))); - zipOS.closeEntry(); - - if (isPause) { - synchronized (pauseLock) { - pauseLock.wait(); + initByteProgress(IO.calcSize(fromFile)); + try (ZipOutputStream zipOutputStream = new ZipOutputStream(new BufferedOutputStream(nonClosing(toStream)))) { + for (File sourceFile : files) { + String name = sourceFile.getAbsolutePath().substring(basePath.length() + 1); + zipOutputStream.putNextEntry(new ZipEntry(normalizeEntryName(name))); + try (InputStream inputStream = IO.getInputStream(sourceFile)) { + transfer(inputStream, zipOutputStream); } + zipOutputStream.closeEntry(); + handleFile(sourceFile); } - if (fileCallback != null) { - fileCallback.handler(toFile); - } - if (progressCallback != null) { - progressCallback.handler(1D * i / total); - } - if (isInterrupt) { - break; - } - } - zipOS.finish(); - zipOS.close(); - byteOS.flush(); - byteOS.close(); - os.flush(); - os.close(); - - if (isInterrupt) { - IO.destroy(toFile); + zipOutputStream.finish(); + finishProgress(); + } finally { + resetProgress(); } } -} \ No newline at end of file +} diff --git a/src/main/java/com/imyeyu/compress/ZipDecompressor.java b/src/main/java/com/imyeyu/compress/ZipDecompressor.java index 8251601..d8f368d 100644 --- a/src/main/java/com/imyeyu/compress/ZipDecompressor.java +++ b/src/main/java/com/imyeyu/compress/ZipDecompressor.java @@ -3,11 +3,16 @@ package com.imyeyu.compress; import com.imyeyu.io.IO; import java.io.File; +import java.io.InputStream; +import java.io.OutputStream; import java.util.Enumeration; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; +import java.util.zip.ZipInputStream; /** + * Zip 解压器 + * * @author 夜雨 * @version 2024-06-30 19:47 */ @@ -15,42 +20,63 @@ public class ZipDecompressor extends Decompressor { @Override public void run(File fromFile, String toPath) throws Exception { - ZipFile zip = new ZipFile(fromFile); - - Enumeration entries = zip.entries(); - int total = 0; - while (entries.hasMoreElements()) { - if (!entries.nextElement().isDirectory()) { - total++; - } + initByteProgress(readTotalSize(fromFile)); + try { + super.run(fromFile, toPath); + } finally { + resetProgress(); } - - entries = zip.entries(); - ZipEntry entry; - for (int i = 0; entries.hasMoreElements(); i++) { - entry = entries.nextElement(); - if (entry.isDirectory()) { - IO.dir(IO.fitPath(toPath) + entry.getName()); - } else { - File toFile = IO.file(IO.fitPath(toPath) + entry.getName()); - IO.toFile(toFile, zip.getInputStream(entry)); - - if (fileCallback != null) { - fileCallback.handler(toFile); - } - } - if (isPause) { - synchronized (pauseLock) { - pauseLock.wait(); - } - } - if (progressCallback != null) { - progressCallback.handler(1D * i / total); - } - if (isInterrupt) { - break; - } - } - zip.close(); } -} \ No newline at end of file + + @Override + public void run(InputStream fromStream, String toPath) throws Exception { + try (ZipInputStream zipInputStream = new ZipInputStream(nonClosing(fromStream))) { + ZipEntry entry; + boolean processed = false; + while ((entry = zipInputStream.getNextEntry()) != null) { + String path = IO.fitPath(toPath) + entry.getName(); + if (entry.isDirectory()) { + IO.dir(path); + } else { + File toFile = IO.file(path); + try (OutputStream outputStream = IO.getOutputStream(toFile)) { + transfer(zipInputStream, outputStream); + outputStream.flush(); + } + handleFile(toFile); + processed = true; + } + zipInputStream.closeEntry(); + } + if (processed) { + finishProgress(); + } + } + } + + /** + * 读取压缩包解压总字节数 + * + * @param fromFile 压缩文件 + * @return 总字节数,未知时返回 -1 + * @throws Exception 读取失败 + */ + private long readTotalSize(File fromFile) throws Exception { + long totalSize = 0L; + try (ZipFile zipFile = new ZipFile(fromFile)) { + Enumeration entries = zipFile.entries(); + while (entries.hasMoreElements()) { + ZipEntry entry = entries.nextElement(); + if (entry.isDirectory()) { + continue; + } + long size = entry.getSize(); + if (size < 0L) { + return -1L; + } + totalSize += size; + } + } + return totalSize; + } +} diff --git a/src/test/java/test/GzipTest.java b/src/test/java/test/GzipTest.java index 4efa22a..5127881 100644 --- a/src/test/java/test/GzipTest.java +++ b/src/test/java/test/GzipTest.java @@ -4,6 +4,8 @@ import com.imyeyu.compress.CompressType; import com.imyeyu.io.IO; import org.junit.jupiter.api.Test; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; import java.io.File; /** @@ -15,7 +17,7 @@ public class GzipTest { @Test public void testCompress() throws Exception { File out = IO.file("testOut/test.gz"); - CompressType.Z7.getCompressor().run("testSrc", out); + CompressType.GZIP.getCompressor().run("testSrc", out); } @Test @@ -24,4 +26,24 @@ public class GzipTest { File out = IO.dir("testOutDe"); CompressType.fromFile(in).run(in, out.getAbsolutePath()); } + + @Test + public void testCompressToStream() throws Exception { + try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { + CompressType.GZIP.getCompressor().run("testSrc", outputStream); + } + } + + @Test + public void testDecompressFromStream() throws Exception { + byte[] bytes; + try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { + CompressType.GZIP.getCompressor().run("testSrc", outputStream); + bytes = outputStream.toByteArray(); + } + File out = IO.dir("testOutDeStream/gzip"); + try (ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes)) { + CompressType.GZIP.getDecompressor().run(inputStream, out.getAbsolutePath()); + } + } } diff --git a/src/test/java/test/TarTest.java b/src/test/java/test/TarTest.java index 12aaffc..69f0e0b 100644 --- a/src/test/java/test/TarTest.java +++ b/src/test/java/test/TarTest.java @@ -4,6 +4,8 @@ import com.imyeyu.compress.CompressType; import com.imyeyu.io.IO; import org.junit.jupiter.api.Test; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; import java.io.File; /** @@ -15,7 +17,7 @@ public class TarTest { @Test public void testCompress() throws Exception { File out = IO.file("testOut/test.tar"); - CompressType.Z7.getCompressor().run("testSrc", out); + CompressType.TAR.getCompressor().run("testSrc", out); } @Test @@ -24,4 +26,24 @@ public class TarTest { File out = IO.dir("testOutDe"); CompressType.fromFile(in).run(in, out.getAbsolutePath()); } + + @Test + public void testCompressToStream() throws Exception { + try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { + CompressType.TAR.getCompressor().run("testSrc", outputStream); + } + } + + @Test + public void testDecompressFromStream() throws Exception { + byte[] bytes; + try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { + CompressType.TAR.getCompressor().run("testSrc", outputStream); + bytes = outputStream.toByteArray(); + } + File out = IO.dir("testOutDeStream/tar"); + try (ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes)) { + CompressType.TAR.getDecompressor().run(inputStream, out.getAbsolutePath()); + } + } } diff --git a/src/test/java/test/Z7Test.java b/src/test/java/test/Z7Test.java index ebf8f26..267697f 100644 --- a/src/test/java/test/Z7Test.java +++ b/src/test/java/test/Z7Test.java @@ -4,6 +4,8 @@ import com.imyeyu.compress.CompressType; import com.imyeyu.io.IO; import org.junit.jupiter.api.Test; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; import java.io.File; /** @@ -24,4 +26,24 @@ public class Z7Test { File out = IO.dir("testOutDe"); CompressType.fromFile(in).run(in, out.getAbsolutePath()); } -} \ No newline at end of file + + @Test + public void testCompressToStream() throws Exception { + try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { + CompressType.Z7.getCompressor().run("testSrc", outputStream); + } + } + + @Test + public void testDecompressFromStream() throws Exception { + byte[] bytes; + try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { + CompressType.Z7.getCompressor().run("testSrc", outputStream); + bytes = outputStream.toByteArray(); + } + File out = IO.dir("testOutDeStream/z7"); + try (ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes)) { + CompressType.Z7.getDecompressor().run(inputStream, out.getAbsolutePath()); + } + } +} diff --git a/src/test/java/test/ZipTest.java b/src/test/java/test/ZipTest.java index a2c8af1..1aa0bca 100644 --- a/src/test/java/test/ZipTest.java +++ b/src/test/java/test/ZipTest.java @@ -4,6 +4,8 @@ import com.imyeyu.compress.CompressType; import com.imyeyu.io.IO; import org.junit.jupiter.api.Test; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; import java.io.File; /** @@ -15,7 +17,7 @@ public class ZipTest { @Test public void testCompress() throws Exception { File out = IO.file("testOut/test.zip"); - CompressType.Z7.getCompressor().run("testSrc", out); + CompressType.ZIP.getCompressor().run("testSrc", out); } @Test @@ -24,4 +26,24 @@ public class ZipTest { File out = IO.dir("testOutDe"); CompressType.fromFile(in).run(in, out.getAbsolutePath()); } + + @Test + public void testCompressToStream() throws Exception { + try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { + CompressType.ZIP.getCompressor().run("testSrc", outputStream); + } + } + + @Test + public void testDecompressFromStream() throws Exception { + byte[] bytes; + try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { + CompressType.ZIP.getCompressor().run("testSrc", outputStream); + bytes = outputStream.toByteArray(); + } + File out = IO.dir("testOutDeStream/zip"); + try (ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes)) { + CompressType.ZIP.getDecompressor().run(inputStream, out.getAbsolutePath()); + } + } } -- 2.49.1