ZipUtility.cs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431
  1. /****************************************************************************
  2. * Copyright 2019 Nreal Techonology Limited. All rights reserved.
  3. *
  4. * This file is part of NRSDK.
  5. *
  6. * https://www.nreal.ai/
  7. *
  8. *****************************************************************************/
  9. namespace NRKernal
  10. {
  11. using System.IO;
  12. using UnityEngine;
  13. using ICSharpCode.SharpZipLib.Zip;
  14. using System;
  15. /// <summary> A zip utility. </summary>
  16. public class ZipUtility
  17. {
  18. #region ZipCallback
  19. /// <summary> A zip callback. </summary>
  20. public class ZipCallback
  21. {
  22. /// <summary> The on pre zip callback. </summary>
  23. public Action<ZipEntry> OnPreZipCallback;
  24. /// <summary> The on post zip callback. </summary>
  25. public Action<ZipEntry> OnPostZipCallback;
  26. /// <summary> The on finished callback. </summary>
  27. public Action<bool> OnFinishedCallback;
  28. /// <summary> Constructor. </summary>
  29. /// <param name="onprezip"> The onprezip.</param>
  30. /// <param name="onpostzip"> The onpostzip.</param>
  31. /// <param name="onfinish"> The onfinish.</param>
  32. public ZipCallback(Action<ZipEntry> onprezip, Action<ZipEntry> onpostzip, Action<bool> onfinish)
  33. {
  34. OnPreZipCallback = onprezip;
  35. OnPostZipCallback = onpostzip;
  36. OnFinishedCallback = onfinish;
  37. }
  38. /// <summary> Constructor. </summary>
  39. /// <param name="onfinish"> The onfinish.</param>
  40. public ZipCallback(Action<bool> onfinish) : this(null, null, onfinish)
  41. {
  42. }
  43. /// <summary> Executes the 'pre zip' action. </summary>
  44. /// <param name="_entry"> The entry.</param>
  45. /// <returns> True if it succeeds, false if it fails. </returns>
  46. public virtual bool OnPreZip(ZipEntry _entry)
  47. {
  48. if (OnPreZipCallback != null)
  49. {
  50. OnPreZipCallback(_entry);
  51. }
  52. return true;
  53. }
  54. /// <summary> Executes the 'post zip' action. </summary>
  55. /// <param name="_entry"> The entry.</param>
  56. public virtual void OnPostZip(ZipEntry _entry)
  57. {
  58. if (OnPostZipCallback != null)
  59. {
  60. OnPostZipCallback(_entry);
  61. }
  62. }
  63. /// <summary> Executes the 'finished' action. </summary>
  64. /// <param name="_result"> True to result.</param>
  65. public virtual void OnFinished(bool _result)
  66. {
  67. if (OnFinishedCallback != null)
  68. {
  69. OnFinishedCallback(_result);
  70. }
  71. }
  72. }
  73. #endregion
  74. #region UnzipCallback
  75. /// <summary> An unzip callback. </summary>
  76. public abstract class UnzipCallback
  77. {
  78. /// <summary> The on pre zip callback. </summary>
  79. public Action<ZipEntry> OnPreZipCallback;
  80. /// <summary> The on post zip callback. </summary>
  81. public Action<ZipEntry> OnPostZipCallback;
  82. /// <summary> The on finished callback. </summary>
  83. public Action<bool> OnFinishedCallback;
  84. /// <summary> Constructor. </summary>
  85. /// <param name="onprezip"> The onprezip.</param>
  86. /// <param name="onpostzip"> The onpostzip.</param>
  87. /// <param name="onfinish"> The onfinish.</param>
  88. public UnzipCallback(Action<ZipEntry> onprezip, Action<ZipEntry> onpostzip, Action<bool> onfinish)
  89. {
  90. OnPreZipCallback = onprezip;
  91. OnPostZipCallback = onpostzip;
  92. OnFinishedCallback = onfinish;
  93. }
  94. /// <summary> Constructor. </summary>
  95. /// <param name="onfinish"> The onfinish.</param>
  96. public UnzipCallback(Action<bool> onfinish) : this(null, null, onfinish)
  97. {
  98. }
  99. /// <summary> Executes the 'pre unzip' action. </summary>
  100. /// <param name="_entry"> The entry.</param>
  101. /// <returns> True if it succeeds, false if it fails. </returns>
  102. public virtual bool OnPreUnzip(ZipEntry _entry)
  103. {
  104. if (OnPreZipCallback != null)
  105. {
  106. OnPreZipCallback(_entry);
  107. }
  108. return true;
  109. }
  110. /// <summary> Executes the 'post unzip' action. </summary>
  111. /// <param name="_entry"> The entry.</param>
  112. public virtual void OnPostUnzip(ZipEntry _entry)
  113. {
  114. if (OnPostZipCallback != null)
  115. {
  116. OnPostZipCallback(_entry);
  117. }
  118. }
  119. /// <summary> Executes the 'finished' action. </summary>
  120. /// <param name="_result"> True to result.</param>
  121. public virtual void OnFinished(bool _result)
  122. {
  123. if (OnFinishedCallback != null)
  124. {
  125. OnFinishedCallback(_result);
  126. }
  127. }
  128. }
  129. #endregion
  130. /// <summary> Zips. </summary>
  131. /// <param name="_fileOrDirectoryArray"> Array of file or directories.</param>
  132. /// <param name="_outputPathName"> Full pathname of the output file.</param>
  133. /// <param name="_password"> (Optional) The password.</param>
  134. /// <param name="_zipCallback"> (Optional) The zip callback.</param>
  135. /// <returns> True if it succeeds, false if it fails. </returns>
  136. public static bool Zip(string[] _fileOrDirectoryArray, string _outputPathName, string _password = null, ZipCallback _zipCallback = null)
  137. {
  138. if ((null == _fileOrDirectoryArray) || string.IsNullOrEmpty(_outputPathName))
  139. {
  140. if (null != _zipCallback)
  141. _zipCallback.OnFinished(false);
  142. return false;
  143. }
  144. ZipOutputStream zipOutputStream = new ZipOutputStream(File.Create(_outputPathName));
  145. zipOutputStream.SetLevel(6); // 压缩质量和压缩速度的平衡点
  146. if (!string.IsNullOrEmpty(_password))
  147. zipOutputStream.Password = _password;
  148. for (int index = 0; index < _fileOrDirectoryArray.Length; ++index)
  149. {
  150. bool result = false;
  151. string fileOrDirectory = _fileOrDirectoryArray[index];
  152. if (Directory.Exists(fileOrDirectory))
  153. result = ZipDirectory(fileOrDirectory, string.Empty, zipOutputStream, _zipCallback);
  154. else if (File.Exists(fileOrDirectory))
  155. result = ZipFile(fileOrDirectory, string.Empty, zipOutputStream, _zipCallback);
  156. if (!result)
  157. {
  158. if (null != _zipCallback)
  159. _zipCallback.OnFinished(false);
  160. return false;
  161. }
  162. }
  163. zipOutputStream.Finish();
  164. zipOutputStream.Close();
  165. if (null != _zipCallback)
  166. _zipCallback.OnFinished(true);
  167. return true;
  168. }
  169. /// <summary> Unzip file. </summary>
  170. /// <param name="_filePathName"> Full pathname of the file file.</param>
  171. /// <param name="_outputPath"> Full pathname of the output file.</param>
  172. /// <param name="_password"> (Optional) The password.</param>
  173. /// <param name="_unzipCallback"> (Optional) The unzip callback.</param>
  174. /// <returns> True if it succeeds, false if it fails. </returns>
  175. public static bool UnzipFile(string _filePathName, string _outputPath, string _password = null, UnzipCallback _unzipCallback = null)
  176. {
  177. if (string.IsNullOrEmpty(_filePathName) || string.IsNullOrEmpty(_outputPath))
  178. {
  179. if (null != _unzipCallback)
  180. _unzipCallback.OnFinished(false);
  181. return false;
  182. }
  183. try
  184. {
  185. return UnzipFile(File.OpenRead(_filePathName), _outputPath, _password, _unzipCallback);
  186. }
  187. catch (System.Exception _e)
  188. {
  189. NRDebugger.Error("[ZipUtility.UnzipFile]: " + _e.ToString());
  190. if (null != _unzipCallback)
  191. _unzipCallback.OnFinished(false);
  192. return false;
  193. }
  194. }
  195. /// <summary> Unzip file. </summary>
  196. /// <param name="_fileBytes"> The file in bytes.</param>
  197. /// <param name="_outputPath"> Full pathname of the output file.</param>
  198. /// <param name="_password"> (Optional) The password.</param>
  199. /// <param name="_unzipCallback"> (Optional) The unzip callback.</param>
  200. /// <returns> True if it succeeds, false if it fails. </returns>
  201. public static bool UnzipFile(byte[] _fileBytes, string _outputPath, string _password = null, UnzipCallback _unzipCallback = null)
  202. {
  203. if ((null == _fileBytes) || string.IsNullOrEmpty(_outputPath))
  204. {
  205. if (null != _unzipCallback)
  206. _unzipCallback.OnFinished(false);
  207. return false;
  208. }
  209. bool result = UnzipFile(new MemoryStream(_fileBytes), _outputPath, _password, _unzipCallback);
  210. if (!result)
  211. {
  212. if (null != _unzipCallback)
  213. _unzipCallback.OnFinished(false);
  214. }
  215. return result;
  216. }
  217. /// <summary> Unzip file. </summary>
  218. /// <param name="_inputStream"> Stream to read data from.</param>
  219. /// <param name="_outputPath"> Full pathname of the output file.</param>
  220. /// <param name="_password"> (Optional) The password.</param>
  221. /// <param name="_unzipCallback"> (Optional) The unzip callback.</param>
  222. /// <returns> True if it succeeds, false if it fails. </returns>
  223. public static bool UnzipFile(Stream _inputStream, string _outputPath, string _password = null, UnzipCallback _unzipCallback = null)
  224. {
  225. if ((null == _inputStream) || string.IsNullOrEmpty(_outputPath))
  226. {
  227. if (null != _unzipCallback)
  228. _unzipCallback.OnFinished(false);
  229. return false;
  230. }
  231. // 创建文件目录
  232. if (!Directory.Exists(_outputPath))
  233. Directory.CreateDirectory(_outputPath);
  234. // 解压Zip包
  235. ZipEntry entry = null;
  236. using (ZipInputStream zipInputStream = new ZipInputStream(_inputStream))
  237. {
  238. if (!string.IsNullOrEmpty(_password))
  239. zipInputStream.Password = _password;
  240. while (null != (entry = zipInputStream.GetNextEntry()))
  241. {
  242. if (string.IsNullOrEmpty(entry.Name))
  243. continue;
  244. if ((null != _unzipCallback) && !_unzipCallback.OnPreUnzip(entry))
  245. continue; // 过滤
  246. string filePathName = Path.Combine(_outputPath, entry.Name);
  247. // 创建文件目录
  248. if (entry.IsDirectory)
  249. {
  250. Directory.CreateDirectory(filePathName);
  251. continue;
  252. }
  253. // 写入文件
  254. try
  255. {
  256. using (FileStream fileStream = File.Create(filePathName))
  257. {
  258. byte[] bytes = new byte[1024];
  259. while (true)
  260. {
  261. int count = zipInputStream.Read(bytes, 0, bytes.Length);
  262. if (count > 0)
  263. fileStream.Write(bytes, 0, count);
  264. else
  265. {
  266. if (null != _unzipCallback)
  267. _unzipCallback.OnPostUnzip(entry);
  268. break;
  269. }
  270. }
  271. }
  272. }
  273. catch (System.Exception _e)
  274. {
  275. NRDebugger.Error("[ZipUtility.UnzipFile]: " + _e.ToString());
  276. if (null != _unzipCallback)
  277. _unzipCallback.OnFinished(false);
  278. return false;
  279. }
  280. }
  281. }
  282. if (null != _unzipCallback)
  283. _unzipCallback.OnFinished(true);
  284. return true;
  285. }
  286. /// <summary> Zip file. </summary>
  287. /// <param name="_filePathName"> Full pathname of the file file.</param>
  288. /// <param name="_parentRelPath"> Full pathname of the parent relative file.</param>
  289. /// <param name="_zipOutputStream"> The zip output stream.</param>
  290. /// <param name="_zipCallback"> (Optional) The zip callback.</param>
  291. /// <returns> True if it succeeds, false if it fails. </returns>
  292. private static bool ZipFile(string _filePathName, string _parentRelPath, ZipOutputStream _zipOutputStream, ZipCallback _zipCallback = null)
  293. {
  294. //Crc32 crc32 = new Crc32();
  295. ZipEntry entry = null;
  296. FileStream fileStream = null;
  297. try
  298. {
  299. string entryName = _parentRelPath + '/' + Path.GetFileName(_filePathName);
  300. entry = new ZipEntry(entryName);
  301. entry.DateTime = System.DateTime.Now;
  302. if ((null != _zipCallback) && !_zipCallback.OnPreZip(entry))
  303. return true; // 过滤
  304. fileStream = File.OpenRead(_filePathName);
  305. byte[] buffer = new byte[fileStream.Length];
  306. fileStream.Read(buffer, 0, buffer.Length);
  307. fileStream.Close();
  308. entry.Size = buffer.Length;
  309. //crc32.Reset();
  310. //crc32.Update(buffer);
  311. //entry.Crc = crc32.Value;
  312. _zipOutputStream.PutNextEntry(entry);
  313. _zipOutputStream.Write(buffer, 0, buffer.Length);
  314. }
  315. catch (System.Exception _e)
  316. {
  317. NRDebugger.Error("[ZipUtility.ZipFile]: " + _e.ToString());
  318. return false;
  319. }
  320. finally
  321. {
  322. if (null != fileStream)
  323. {
  324. fileStream.Close();
  325. fileStream.Dispose();
  326. }
  327. }
  328. if (null != _zipCallback)
  329. _zipCallback.OnPostZip(entry);
  330. return true;
  331. }
  332. /// <summary> Zip directory. </summary>
  333. /// <param name="_path"> Full pathname of the file.</param>
  334. /// <param name="_parentRelPath"> Full pathname of the parent relative file.</param>
  335. /// <param name="_zipOutputStream"> The zip output stream.</param>
  336. /// <param name="_zipCallback"> (Optional) The zip callback.</param>
  337. /// <returns> True if it succeeds, false if it fails. </returns>
  338. private static bool ZipDirectory(string _path, string _parentRelPath, ZipOutputStream _zipOutputStream, ZipCallback _zipCallback = null)
  339. {
  340. ZipEntry entry = null;
  341. try
  342. {
  343. string entryName = Path.Combine(_parentRelPath, Path.GetFileName(_path) + '/');
  344. entry = new ZipEntry(entryName);
  345. entry.DateTime = System.DateTime.Now;
  346. entry.Size = 0;
  347. if ((null != _zipCallback) && !_zipCallback.OnPreZip(entry))
  348. return true; // 过滤
  349. _zipOutputStream.PutNextEntry(entry);
  350. _zipOutputStream.Flush();
  351. string[] files = Directory.GetFiles(_path);
  352. for (int index = 0; index < files.Length; ++index)
  353. ZipFile(files[index], Path.Combine(_parentRelPath, Path.GetFileName(_path)), _zipOutputStream, _zipCallback);
  354. }
  355. catch (System.Exception _e)
  356. {
  357. NRDebugger.Error("[ZipUtility.ZipDirectory]: " + _e.ToString());
  358. return false;
  359. }
  360. string[] directories = Directory.GetDirectories(_path);
  361. for (int index = 0; index < directories.Length; ++index)
  362. {
  363. if (!ZipDirectory(directories[index], Path.Combine(_parentRelPath, Path.GetFileName(_path)), _zipOutputStream, _zipCallback))
  364. return false;
  365. }
  366. if (null != _zipCallback)
  367. _zipCallback.OnPostZip(entry);
  368. return true;
  369. }
  370. }
  371. }