From 7db0d3fcc4c482fe9b9fec94661f1ec1b666c294 Mon Sep 17 00:00:00 2001
From: ALEXTANG <574809918@qq.com>
Date: Tue, 25 Apr 2023 15:44:29 +0800
Subject: [PATCH] [+] ZipWrapper
[+] ZipWrapper
---
Assets/TEngine/Runtime/Utility/ZipWrapper.cs | 396 ++++++++++++++++++
.../Runtime/Utility/ZipWrapper.cs.meta | 11 +
2 files changed, 407 insertions(+)
create mode 100644 Assets/TEngine/Runtime/Utility/ZipWrapper.cs
create mode 100644 Assets/TEngine/Runtime/Utility/ZipWrapper.cs.meta
diff --git a/Assets/TEngine/Runtime/Utility/ZipWrapper.cs b/Assets/TEngine/Runtime/Utility/ZipWrapper.cs
new file mode 100644
index 00000000..5d28eb93
--- /dev/null
+++ b/Assets/TEngine/Runtime/Utility/ZipWrapper.cs
@@ -0,0 +1,396 @@
+using ICSharpCode.SharpZipLib.Zip;
+using System.IO;
+using ICSharpCode.SharpZipLib.Checksums;
+using UnityEngine;
+
+public class ZipWrapper : MonoBehaviour
+{
+ #region ZipCallback
+
+ public abstract class ZipCallback
+ {
+ ///
+ /// 压缩单个文件或文件夹前执行的回调。
+ ///
+ /// 压缩实例。
+ /// 如果返回true,则压缩文件或文件夹,反之则不压缩文件或文件夹。
+ public virtual bool OnPreZip(ZipEntry entry)
+ {
+ return true;
+ }
+
+ ///
+ /// 压缩单个文件或文件夹后执行的回调。
+ ///
+ /// 压缩实例。
+ public virtual void OnPostZip(ZipEntry entry)
+ {
+ }
+
+ ///
+ /// 压缩执行完毕后的回调。
+ ///
+ /// true表示压缩成功,false表示压缩失败。
+ public virtual void OnFinished(bool result)
+ {
+ }
+ }
+
+ #endregion
+
+ #region UnzipCallback
+
+ public abstract class UnzipCallback
+ {
+ ///
+ /// 解压单个文件或文件夹前执行的回调。
+ ///
+ /// 压缩实例。
+ /// 如果返回true,则压缩文件或文件夹,反之则不压缩文件或文件夹。
+ public virtual bool OnPreUnzip(ZipEntry entry)
+ {
+ return true;
+ }
+
+ ///
+ /// 解压单个文件或文件夹后执行的回调。
+ ///
+ /// 压缩实例。
+ public virtual void OnPostUnzip(ZipEntry entry)
+ {
+ }
+
+ ///
+ /// 解压执行完毕后的回调。
+ ///
+ /// true表示解压成功,false表示解压失败。
+ public virtual void OnFinished(bool result)
+ {
+ }
+ }
+
+ #endregion
+
+ ///
+ /// 压缩文件和文件夹。
+ ///
+ /// 文件夹路径和文件名。
+ /// 压缩后的输出路径文件名。
+ /// 压缩密码。
+ /// ZipCallback对象,负责回调。
+ ///
+ public static bool Zip(string[] fileOrDirectoryArray, string outputPathName, string password = null, ZipCallback zipCallback = null)
+ {
+ if ((null == fileOrDirectoryArray) || string.IsNullOrEmpty(outputPathName))
+ {
+ if (null != zipCallback)
+ zipCallback.OnFinished(false);
+
+ return false;
+ }
+
+ ZipOutputStream zipOutputStream = new ZipOutputStream(File.Create(outputPathName));
+ // 压缩质量和压缩速度的平衡点
+ zipOutputStream.SetLevel(6);
+ if (!string.IsNullOrEmpty(password))
+ zipOutputStream.Password = password;
+
+ for (int index = 0; index < fileOrDirectoryArray.Length; ++index)
+ {
+ bool result = false;
+ string fileOrDirectory = fileOrDirectoryArray[index];
+ if (Directory.Exists(fileOrDirectory))
+ result = ZipDirectory(fileOrDirectory, string.Empty, zipOutputStream, zipCallback);
+ else if (File.Exists(fileOrDirectory))
+ result = ZipFile(fileOrDirectory, string.Empty, zipOutputStream, zipCallback);
+
+ if (!result)
+ {
+ if (null != zipCallback)
+ zipCallback.OnFinished(false);
+
+ return false;
+ }
+ }
+
+ zipOutputStream.Finish();
+ zipOutputStream.Close();
+
+ if (null != zipCallback)
+ zipCallback.OnFinished(true);
+
+ return true;
+ }
+
+ ///
+ /// 解压Zip包。
+ ///
+ /// Zip包的文件路径名。
+ /// 解压输出路径。
+ /// 解压密码。
+ /// UnzipCallback对象,负责回调。
+ ///
+ public static bool UnzipFile(string filePathName, string outputPath, string password = null, UnzipCallback unzipCallback = null)
+ {
+ if (string.IsNullOrEmpty(filePathName) || string.IsNullOrEmpty(outputPath))
+ {
+ if (null != unzipCallback)
+ unzipCallback.OnFinished(false);
+
+ return false;
+ }
+
+ try
+ {
+ return UnzipFile(File.OpenRead(filePathName), outputPath, password, unzipCallback);
+ }
+ catch (System.Exception exception)
+ {
+ Debug.LogError("[ZipUtility.UnzipFile]: " + exception);
+
+ if (null != unzipCallback)
+ unzipCallback.OnFinished(false);
+
+ return false;
+ }
+ }
+
+ ///
+ /// 解压Zip包。
+ ///
+ /// Zip包字节数组。
+ /// 解压输出路径。
+ /// 解压密码。
+ /// UnzipCallback对象,负责回调。
+ ///
+ public static bool UnzipFile(byte[] fileBytes, string outputPath, string password = null, UnzipCallback unzipCallback = null)
+ {
+ if ((null == fileBytes) || string.IsNullOrEmpty(outputPath))
+ {
+ if (null != unzipCallback)
+ unzipCallback.OnFinished(false);
+
+ return false;
+ }
+
+ bool result = UnzipFile(new MemoryStream(fileBytes), outputPath, password, unzipCallback);
+ if (!result)
+ {
+ if (null != unzipCallback)
+ unzipCallback.OnFinished(false);
+ }
+
+ return result;
+ }
+
+ ///
+ /// 解压Zip包
+ ///
+ /// Zip包输入流。
+ /// 解压输出路径。
+ /// 解压密码。
+ /// UnzipCallback对象,负责回调。
+ ///
+ public static bool UnzipFile(Stream inputStream, string outputPath, string password = null, UnzipCallback unzipCallback = null)
+ {
+ if ((null == inputStream) || string.IsNullOrEmpty(outputPath))
+ {
+ if (null != unzipCallback)
+ unzipCallback.OnFinished(false);
+
+ return false;
+ }
+
+ // 创建文件目录
+ if (!Directory.Exists(outputPath))
+ Directory.CreateDirectory(outputPath);
+
+ // 解压Zip包
+ ZipEntry zipEntry = null;
+ using (ZipInputStream zipInputStream = new ZipInputStream(inputStream))
+ {
+ if (!string.IsNullOrEmpty(password))
+ zipInputStream.Password = password;
+
+ while (null != (zipEntry = zipInputStream.GetNextEntry()))
+ {
+ if (string.IsNullOrEmpty(zipEntry.Name))
+ continue;
+
+ if ((null != unzipCallback) && !unzipCallback.OnPreUnzip(zipEntry))
+ continue; // 过滤
+
+ string filePathName = Path.Combine(outputPath, zipEntry.Name);
+
+ // 创建文件目录
+ if (zipEntry.IsDirectory)
+ {
+ Directory.CreateDirectory(filePathName);
+ continue;
+ }
+
+ // 写入文件
+ try
+ {
+ using (FileStream fileStream = File.Create(filePathName))
+ {
+ byte[] bytes = new byte[1024];
+ while (true)
+ {
+ int count = zipInputStream.Read(bytes, 0, bytes.Length);
+ if (count > 0)
+ fileStream.Write(bytes, 0, count);
+ else
+ {
+ if (null != unzipCallback)
+ unzipCallback.OnPostUnzip(zipEntry);
+
+ break;
+ }
+ }
+ }
+ }
+ catch (System.Exception exception)
+ {
+ Debug.LogError($"[ZipUtility.UnzipFile]: {exception}");
+
+ if (null != unzipCallback)
+ unzipCallback.OnFinished(false);
+
+ return false;
+ }
+ }
+ }
+
+ if (null != unzipCallback)
+ {
+ unzipCallback.OnFinished(true);
+ }
+
+ return true;
+ }
+
+ ///
+ /// 压缩文件。
+ ///
+ /// 文件路径名。
+ /// 要压缩的文件的父相对文件夹。
+ /// 压缩输出流。
+ /// ZipCallback对象,负责回调。
+ /// 是否使用Crc。
+ ///
+ private static bool ZipFile(string filePathName, string parentRelPath, ZipOutputStream zipOutputStream, ZipCallback zipCallback = null, bool useCrc = false)
+ {
+ ZipEntry entry = null;
+ FileStream fileStream = null;
+ try
+ {
+ string entryName = $"{parentRelPath}/{Path.GetFileName(filePathName)}";
+ entry = new ZipEntry(entryName);
+ entry.DateTime = System.DateTime.Now;
+
+ if ((null != zipCallback) && !zipCallback.OnPreZip(entry))
+ return true; // 过滤
+
+ fileStream = File.OpenRead(filePathName);
+ byte[] buffer = new byte[fileStream.Length];
+ var read = fileStream.Read(buffer, 0, buffer.Length);
+ fileStream.Close();
+
+ entry.Size = buffer.Length;
+
+ if (useCrc)
+ {
+ Crc32 crc32 = new Crc32();
+ crc32.Reset();
+ crc32.Update(buffer);
+ entry.Crc = crc32.Value;
+ }
+
+ zipOutputStream.PutNextEntry(entry);
+ zipOutputStream.Write(buffer, 0, buffer.Length);
+ }
+ catch (System.Exception exception)
+ {
+ Debug.LogError($"[ZipUtility.ZipFile]: {exception}");
+ return false;
+ }
+ finally
+ {
+ if (null != fileStream)
+ {
+ fileStream.Close();
+ fileStream.Dispose();
+ }
+ }
+
+ if (null != zipCallback)
+ zipCallback.OnPostZip(entry);
+
+ return true;
+ }
+
+ ///
+ /// 压缩文件夹。
+ ///
+ /// 要压缩的文件夹。
+ /// 要压缩的文件夹的父相对文件夹。
+ /// 压缩输出流。
+ /// ZipCallback对象,负责回调。
+ ///
+ private static bool ZipDirectory(string path, string parentRelPath, ZipOutputStream zipOutputStream, ZipCallback zipCallback = null)
+ {
+ ZipEntry entry = null;
+ try
+ {
+ string entryName = Path.Combine(parentRelPath, Path.GetFileName(path) + '/');
+ entry = new ZipEntry(entryName)
+ {
+ DateTime = System.DateTime.Now,
+ Size = 0
+ };
+
+ if ((null != zipCallback) && !zipCallback.OnPreZip(entry))
+ {
+ return true; // 过滤
+ }
+
+ zipOutputStream.PutNextEntry(entry);
+ zipOutputStream.Flush();
+
+ string[] files = Directory.GetFiles(path);
+ foreach (var file in files)
+ {
+ // 排除Unity中可能的 .meta 文件
+ if (file.EndsWith(".meta") == true)
+ {
+ Debug.LogWarning(file + " not to zip");
+ continue;
+ }
+
+ ZipFile(file, Path.Combine(parentRelPath, Path.GetFileName(path)), zipOutputStream, zipCallback);
+ }
+ }
+ catch (System.Exception exception)
+ {
+ Debug.LogError($"[ZipUtility.ZipDirectory]: {exception}");
+ return false;
+ }
+
+ string[] directories = Directory.GetDirectories(path);
+ foreach (var directory in directories)
+ {
+ if (!ZipDirectory(directory, Path.Combine(parentRelPath, Path.GetFileName(path)), zipOutputStream, zipCallback))
+ {
+ return false;
+ }
+ }
+
+ if (null != zipCallback)
+ {
+ zipCallback.OnPostZip(entry);
+ }
+
+ return true;
+ }
+}
\ No newline at end of file
diff --git a/Assets/TEngine/Runtime/Utility/ZipWrapper.cs.meta b/Assets/TEngine/Runtime/Utility/ZipWrapper.cs.meta
new file mode 100644
index 00000000..7253bbd4
--- /dev/null
+++ b/Assets/TEngine/Runtime/Utility/ZipWrapper.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 6fe4e40c2c1a9ed41bc5fb538c4b09c7
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant: