diff --git a/.gitignore b/.gitignore
index c6d98d1..a263bb0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,98 +1,40 @@
-# ---> JetBrains
-# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
-# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
-
-# User-specific stuff
-.idea/**/workspace.xml
-.idea/**/tasks.xml
-.idea/**/usage.statistics.xml
-.idea/**/dictionaries
-.idea/**/shelf
-
-# AWS User-specific
-.idea/**/aws.xml
-
-# Generated files
-.idea/**/contentModel.xml
-
-# Sensitive or high-churn files
-.idea/**/dataSources/
-.idea/**/dataSources.ids
-.idea/**/dataSources.local.xml
-.idea/**/sqlDataSources.xml
-.idea/**/dynamic.xml
-.idea/**/uiDesigner.xml
-.idea/**/dbnavigator.xml
-
-# Gradle
-.idea/**/gradle.xml
-.idea/**/libraries
-
-# Gradle and Maven with auto-import
-# When using Gradle or Maven with auto-import, you should exclude module files,
-# since they will be recreated, and may cause churn. Uncomment if using
-# auto-import.
-# .idea/artifacts
-# .idea/compiler.xml
-# .idea/jarRepositories.xml
-# .idea/modules.xml
-# .idea/*.iml
-# .idea/modules
-# *.iml
-# *.ipr
-
-# CMake
-cmake-build-*/
-
-# Mongo Explorer plugin
-.idea/**/mongoSettings.xml
-
-# File-based project format
-*.iws
-
-# IntelliJ
-out/
-
-# mpeltonen/sbt-idea plugin
-.idea_modules/
-
-# JIRA plugin
-atlassian-ide-plugin.xml
-
-# Cursive Clojure plugin
-.idea/replstate.xml
-
-# SonarLint plugin
-.idea/sonarlint/
-
-# Crashlytics plugin (for Android Studio and IntelliJ)
-com_crashlytics_export_strings.xml
-crashlytics.properties
-crashlytics-build.properties
-fabric.properties
-
-# Editor-based Rest Client
-.idea/httpRequests
-
-# Android studio 3.1+ serialized cache file
-.idea/caches/build_file_checksums.ser
-
-# ---> Maven
target/
-pom.xml.tag
-pom.xml.releaseBackup
-pom.xml.versionsBackup
-pom.xml.next
-release.properties
-dependency-reduced-pom.xml
-buildNumber.properties
-.mvn/timing.properties
-# https://github.com/takari/maven-wrapper#usage-without-binary-jar
-.mvn/wrapper/maven-wrapper.jar
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**/target/
+!**/src/test/**/target/
-# Eclipse m2e generated files
-# Eclipse Core
-.project
-# JDT-specific (Eclipse Java Development Tools)
+### IntelliJ IDEA ###
+.idea/modules.xml
+.idea/jarRepositories.xml
+.idea/compiler.xml
+.idea/libraries/
+*.iws
+*.iml
+*.ipr
+
+### Eclipse ###
+.apt_generated
.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### VS Code ###
+.vscode/
+
+### Mac OS ###
+.DS_Store
+
+/testOut*
diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..26d3352
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,3 @@
+# Default ignored files
+/shelf/
+/workspace.xml
diff --git a/.idea/encodings.xml b/.idea/encodings.xml
new file mode 100644
index 0000000..aa00ffa
--- /dev/null
+++ b/.idea/encodings.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..fdc35ea
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml
new file mode 100644
index 0000000..2b63946
--- /dev/null
+++ b/.idea/uiDesigner.xml
@@ -0,0 +1,124 @@
+
+
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+
+
+ -
+
+
+ -
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..35eb1dd
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..b4f3e4e
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,56 @@
+
+
+ 4.0.0
+
+ com.imyeyu.compress
+ timi-compress
+ 0.0.1
+
+
+ true
+ 21
+ 21
+ UTF-8
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.11.0
+
+ 21
+ 21
+ UTF-8
+
+
+
+
+
+
+
+ com.imyeyu.io
+ timi-io
+ 0.0.1
+
+
+ org.apache.commons
+ commons-compress
+ 1.26.1
+
+
+ org.tukaani
+ xz
+ 1.9
+
+
+ org.junit.jupiter
+ junit-jupiter-api
+ 5.10.2
+ test
+
+
+
diff --git a/src/main/java/com/imyeyu/compress/AbstractCompressor.java b/src/main/java/com/imyeyu/compress/AbstractCompressor.java
new file mode 100644
index 0000000..e592565
--- /dev/null
+++ b/src/main/java/com/imyeyu/compress/AbstractCompressor.java
@@ -0,0 +1,66 @@
+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/CompressType.java b/src/main/java/com/imyeyu/compress/CompressType.java
new file mode 100644
index 0000000..db27f55
--- /dev/null
+++ b/src/main/java/com/imyeyu/compress/CompressType.java
@@ -0,0 +1,91 @@
+package com.imyeyu.compress;
+
+import com.imyeyu.io.IO;
+import com.imyeyu.java.ref.Ref;
+
+import java.io.File;
+import java.io.InputStream;
+
+/**
+ * 压缩算法类型
+ *
+ * @author 夜雨
+ * @version 2024-06-30 18:03
+ */
+public enum CompressType {
+
+ /** 7z */
+ Z7(Z7Compressor.class, Z7Decompressor.class, -0x51),
+
+ /** Zip */
+ ZIP(ZipCompressor.class, ZipDecompressor.class, 0x504B0304),
+
+ /** Gzip */
+ GZIP(GZipCompressor.class, GZipDecompressor.class, -0x74F7F8),
+
+ /** tar */
+ TAR(TarCompressor.class, TarDecompressor.class, 0x776F7264);
+
+ /** 压缩类 */
+ final Class extends Compressor> compressorType;
+
+ /** 解压类 */
+ final Class extends Decompressor> decompressorType;
+
+ /** 文件头标记 */
+ final int headHex;
+
+ CompressType(Class extends Compressor> compressorType, Class extends Decompressor> decompressorType, int headHex) {
+ this.compressorType = compressorType;
+ this.decompressorType = decompressorType;
+ this.headHex = headHex;
+ }
+
+ /**
+ * 获取压缩操作对象
+ *
+ * @return 压缩操作对象
+ * @throws Exception 实例化失败
+ */
+ public Compressor getCompressor() throws Exception {
+ return Ref.newInstance(compressorType);
+ }
+
+ /**
+ * 获取解压操作对象
+ *
+ * @return 解压操作对象
+ * @throws Exception 实例化失败
+ */
+ public Decompressor getDecompressor() throws Exception {
+ return Ref.newInstance(decompressorType);
+ }
+
+ /**
+ * 根据文件获取解压操作对象。将会读取文件头解析算法类型
+ *
+ * @param file 文件
+ * @return 解压操作对象
+ * @throws UnsupportedOperationException 不支持的文件
+ * @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();
+ }
+ }
+ 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
new file mode 100644
index 0000000..0191c91
--- /dev/null
+++ b/src/main/java/com/imyeyu/compress/Compressor.java
@@ -0,0 +1,14 @@
+package com.imyeyu.compress;
+
+import java.io.File;
+
+/**
+ *
+ *
+ * @author 夜雨
+ * @version 2024-06-30 10:34
+ */
+public abstract class Compressor extends AbstractCompressor {
+
+ public abstract void run(String fromPath, File toFile) throws Exception;
+}
diff --git a/src/main/java/com/imyeyu/compress/Decompressor.java b/src/main/java/com/imyeyu/compress/Decompressor.java
new file mode 100644
index 0000000..e21dbbc
--- /dev/null
+++ b/src/main/java/com/imyeyu/compress/Decompressor.java
@@ -0,0 +1,21 @@
+package com.imyeyu.compress;
+
+import java.io.File;
+
+/**
+ * 抽象解压
+ *
+ * @author 夜雨
+ * @version 2024-06-30 18:02
+ */
+public abstract class Decompressor extends AbstractCompressor {
+
+ /**
+ * 执行解压
+ *
+ * @param fromFile 来源压缩文件
+ * @param toPath 解压路径
+ * @throws Exception 解压失败
+ */
+ public abstract void run(File fromFile, String toPath) throws Exception;
+}
diff --git a/src/main/java/com/imyeyu/compress/GZipCompressor.java b/src/main/java/com/imyeyu/compress/GZipCompressor.java
new file mode 100644
index 0000000..e3531cc
--- /dev/null
+++ b/src/main/java/com/imyeyu/compress/GZipCompressor.java
@@ -0,0 +1,60 @@
+package com.imyeyu.compress;
+
+import com.imyeyu.io.IO;
+import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
+import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
+import org.apache.commons.compress.compressors.gzip.GzipCompressorOutputStream;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.OutputStream;
+import java.util.List;
+
+/**
+ * @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));
+ 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();
+ }
+ }
+ if (fileCallback != null) {
+ fileCallback.handler(toFile);
+ }
+ if (progressCallback != null) {
+ progressCallback.handler(1D * i / total);
+ }
+ if (isInterrupt) {
+ break;
+ }
+ }
+ 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
new file mode 100644
index 0000000..09e7632
--- /dev/null
+++ b/src/main/java/com/imyeyu/compress/GZipDecompressor.java
@@ -0,0 +1,66 @@
+package com.imyeyu.compress;
+
+import com.imyeyu.io.IO;
+import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
+import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
+import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream;
+
+import java.io.File;
+import java.io.InputStream;
+
+/**
+ * @author 夜雨
+ * @version 2024-06-30 19:47
+ */
+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);
+
+ int total = 0;
+ {
+ TarArchiveEntry entry;
+ while ((entry = tarIS.getNextEntry()) != null) {
+ if (!entry.isDirectory()) {
+ total++;
+ }
+ }
+ }
+ 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();
+ }
+}
diff --git a/src/main/java/com/imyeyu/compress/TarCompressor.java b/src/main/java/com/imyeyu/compress/TarCompressor.java
new file mode 100644
index 0000000..ed0d631
--- /dev/null
+++ b/src/main/java/com/imyeyu/compress/TarCompressor.java
@@ -0,0 +1,61 @@
+package com.imyeyu.compress;
+
+import com.imyeyu.io.IO;
+import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
+import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.OutputStream;
+import java.util.List;
+
+/**
+ * @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));
+ 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();
+ }
+ }
+ 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);
+ }
+ }
+}
diff --git a/src/main/java/com/imyeyu/compress/TarDecompressor.java b/src/main/java/com/imyeyu/compress/TarDecompressor.java
new file mode 100644
index 0000000..e893224
--- /dev/null
+++ b/src/main/java/com/imyeyu/compress/TarDecompressor.java
@@ -0,0 +1,63 @@
+package com.imyeyu.compress;
+
+import com.imyeyu.io.IO;
+import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
+import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
+
+import java.io.File;
+import java.io.InputStream;
+
+/**
+ * @author 夜雨
+ * @version 2024-06-30 19:48
+ */
+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);
+
+ int total = 0;
+ {
+ TarArchiveEntry entry;
+ while ((entry = tarIS.getNextEntry()) != null) {
+ if (!entry.isDirectory()) {
+ total++;
+ }
+ }
+ }
+ 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();
+ }
+}
diff --git a/src/main/java/com/imyeyu/compress/Z7Compressor.java b/src/main/java/com/imyeyu/compress/Z7Compressor.java
new file mode 100644
index 0000000..943ffb9
--- /dev/null
+++ b/src/main/java/com/imyeyu/compress/Z7Compressor.java
@@ -0,0 +1,50 @@
+package com.imyeyu.compress;
+
+import com.imyeyu.io.IO;
+import org.apache.commons.compress.archivers.sevenz.SevenZArchiveEntry;
+import org.apache.commons.compress.archivers.sevenz.SevenZOutputFile;
+
+import java.io.File;
+import java.util.List;
+
+/**
+ * @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;
+ }
+ }
+ out.close();
+ if (isInterrupt) {
+ IO.destroy(toFile);
+ }
+ }
+}
diff --git a/src/main/java/com/imyeyu/compress/Z7Decompressor.java b/src/main/java/com/imyeyu/compress/Z7Decompressor.java
new file mode 100644
index 0000000..c65e73e
--- /dev/null
+++ b/src/main/java/com/imyeyu/compress/Z7Decompressor.java
@@ -0,0 +1,57 @@
+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;
+
+/**
+ * @author 夜雨
+ * @version 2024-06-30 19:42
+ */
+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++;
+ }
+ }
+ }
+ 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);
+ }
+ }
+ if (isPause) {
+ synchronized (pauseLock) {
+ pauseLock.wait();
+ }
+ }
+ if (progressCallback != null && total != -1) {
+ progressCallback.handler(1D * i / total);
+ }
+ if (isInterrupt) {
+ break;
+ }
+ }
+ file.close();
+ }
+}
diff --git a/src/main/java/com/imyeyu/compress/ZipCompressor.java b/src/main/java/com/imyeyu/compress/ZipCompressor.java
new file mode 100644
index 0000000..2d384ba
--- /dev/null
+++ b/src/main/java/com/imyeyu/compress/ZipCompressor.java
@@ -0,0 +1,60 @@
+package com.imyeyu.compress;
+
+import com.imyeyu.io.IO;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.OutputStream;
+import java.util.List;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+
+/**
+ * @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));
+ 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();
+ }
+ }
+ 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);
+ }
+ }
+}
\ 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
new file mode 100644
index 0000000..8251601
--- /dev/null
+++ b/src/main/java/com/imyeyu/compress/ZipDecompressor.java
@@ -0,0 +1,56 @@
+package com.imyeyu.compress;
+
+import com.imyeyu.io.IO;
+
+import java.io.File;
+import java.util.Enumeration;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+/**
+ * @author 夜雨
+ * @version 2024-06-30 19:47
+ */
+public class ZipDecompressor extends Decompressor {
+
+ @Override
+ public void run(File fromFile, String toPath) throws Exception {
+ ZipFile zip = new ZipFile(fromFile);
+
+ Enumeration extends ZipEntry> entries = zip.entries();
+ int total = 0;
+ while (entries.hasMoreElements()) {
+ if (!entries.nextElement().isDirectory()) {
+ total++;
+ }
+ }
+
+ 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
diff --git a/src/test/java/test/ClearTest.java b/src/test/java/test/ClearTest.java
new file mode 100644
index 0000000..1e1565b
--- /dev/null
+++ b/src/test/java/test/ClearTest.java
@@ -0,0 +1,21 @@
+package test;
+
+import com.imyeyu.io.IO;
+import org.junit.jupiter.api.Test;
+
+import java.io.File;
+
+/**
+ * @author 夜雨
+ * @version 2024-06-30 23:54
+ */
+public class ClearTest {
+
+ @Test
+ public void clearTestFiles() throws Exception {
+ IO.destroy(new File("testOut"));
+ IO.dir("testOut");
+ IO.destroy(new File("testOutDe"));
+ IO.dir("testOutDe");
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/test/GzipTest.java b/src/test/java/test/GzipTest.java
new file mode 100644
index 0000000..4efa22a
--- /dev/null
+++ b/src/test/java/test/GzipTest.java
@@ -0,0 +1,27 @@
+package test;
+
+import com.imyeyu.compress.CompressType;
+import com.imyeyu.io.IO;
+import org.junit.jupiter.api.Test;
+
+import java.io.File;
+
+/**
+ * @author 夜雨
+ * @version 2024-06-30 17:54
+ */
+public class GzipTest {
+
+ @Test
+ public void testCompress() throws Exception {
+ File out = IO.file("testOut/test.gz");
+ CompressType.Z7.getCompressor().run("testSrc", out);
+ }
+
+ @Test
+ public void testDecompress() throws Exception {
+ File in = IO.file("testOut/test.gz");
+ File out = IO.dir("testOutDe");
+ CompressType.fromFile(in).run(in, out.getAbsolutePath());
+ }
+}
diff --git a/src/test/java/test/TarTest.java b/src/test/java/test/TarTest.java
new file mode 100644
index 0000000..12aaffc
--- /dev/null
+++ b/src/test/java/test/TarTest.java
@@ -0,0 +1,27 @@
+package test;
+
+import com.imyeyu.compress.CompressType;
+import com.imyeyu.io.IO;
+import org.junit.jupiter.api.Test;
+
+import java.io.File;
+
+/**
+ * @author 夜雨
+ * @version 2024-06-30 17:54
+ */
+public class TarTest {
+
+ @Test
+ public void testCompress() throws Exception {
+ File out = IO.file("testOut/test.tar");
+ CompressType.Z7.getCompressor().run("testSrc", out);
+ }
+
+ @Test
+ public void testDecompress() throws Exception {
+ File in = IO.file("testOut/test.tar");
+ File out = IO.dir("testOutDe");
+ CompressType.fromFile(in).run(in, out.getAbsolutePath());
+ }
+}
diff --git a/src/test/java/test/Z7Test.java b/src/test/java/test/Z7Test.java
new file mode 100644
index 0000000..ebf8f26
--- /dev/null
+++ b/src/test/java/test/Z7Test.java
@@ -0,0 +1,27 @@
+package test;
+
+import com.imyeyu.compress.CompressType;
+import com.imyeyu.io.IO;
+import org.junit.jupiter.api.Test;
+
+import java.io.File;
+
+/**
+ * @author 夜雨
+ * @version 2024-06-30 10:53
+ */
+public class Z7Test {
+
+ @Test
+ public void testCompress() throws Exception {
+ File out = IO.file("testOut/test.7z");
+ CompressType.Z7.getCompressor().run("testSrc", out);
+ }
+
+ @Test
+ public void testDecompress() throws Exception {
+ File in = IO.file("testOut/test.7z");
+ File out = IO.dir("testOutDe");
+ CompressType.fromFile(in).run(in, out.getAbsolutePath());
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/test/ZipTest.java b/src/test/java/test/ZipTest.java
new file mode 100644
index 0000000..a2c8af1
--- /dev/null
+++ b/src/test/java/test/ZipTest.java
@@ -0,0 +1,27 @@
+package test;
+
+import com.imyeyu.compress.CompressType;
+import com.imyeyu.io.IO;
+import org.junit.jupiter.api.Test;
+
+import java.io.File;
+
+/**
+ * @author 夜雨
+ * @version 2024-06-30 17:54
+ */
+public class ZipTest {
+
+ @Test
+ public void testCompress() throws Exception {
+ File out = IO.file("testOut/test.zip");
+ CompressType.Z7.getCompressor().run("testSrc", out);
+ }
+
+ @Test
+ public void testDecompress() throws Exception {
+ File in = IO.file("testOut/test.zip");
+ File out = IO.dir("testOutDe");
+ CompressType.fromFile(in).run(in, out.getAbsolutePath());
+ }
+}
diff --git a/testSrc/file.txt b/testSrc/file.txt
new file mode 100644
index 0000000..3ebaf0c
--- /dev/null
+++ b/testSrc/file.txt
@@ -0,0 +1 @@
+file test
\ No newline at end of file
diff --git a/testSrc/subDir/subFile.txt b/testSrc/subDir/subFile.txt
new file mode 100644
index 0000000..fd6ff5b
--- /dev/null
+++ b/testSrc/subDir/subFile.txt
@@ -0,0 +1 @@
+sub file test
\ No newline at end of file
diff --git a/testSrc/subDir/subFile2.txt b/testSrc/subDir/subFile2.txt
new file mode 100644
index 0000000..836abe5
--- /dev/null
+++ b/testSrc/subDir/subFile2.txt
@@ -0,0 +1 @@
+sub file test2
\ No newline at end of file