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: