123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250 |
- using System;
- using System.ComponentModel;
- using System.IO;
- using System.Text;
- using System.Threading;
- using SharpCompress.Archives;
- using SharpCompress.Common;
- using SharpCompress.Readers;
- using Update.Net.Events;
- namespace Update.Net
- {
- partial class UpdateClient
- {
- private DecompressDataStartDelegate m_DecompressDataStart; //异步解压委托
- private SendOrPostCallback m_ReportDecompressProgressChanged; //解压进度报告回调
- private SendOrPostCallback m_DecompressDataOperationCompleted; //解压操作完成回调
- #region 事件
- //解压进度
- private static readonly object EVENT_DECOMPRESS_PROGRESS_CHANGED = new object();
- /// <summary>
- /// 解压进度事件
- /// </summary>
- public event DecompressProgressChangedEventHandler DecompressProgressChanged
- {
- add { this.Events.AddHandler(EVENT_DECOMPRESS_PROGRESS_CHANGED, value); }
- remove { this.Events.RemoveHandler(EVENT_DECOMPRESS_PROGRESS_CHANGED, value); }
- }
- /// <summary>
- /// 触发解压进度事件
- /// </summary>
- /// <param name="e">数据</param>
- protected virtual void OnDecompressProgressChanged(DecompressProgressChangedEventArgs e)
- {
- DecompressProgressChangedEventHandler handler = this.Events[EVENT_DECOMPRESS_PROGRESS_CHANGED] as DecompressProgressChangedEventHandler;
- if (handler != null)
- handler(this, e);
- }
- /// <summary>
- /// 触发解压进度事件
- /// </summary>
- /// <param name="state">数据</param>
- private void ReportDecompressProgressChanged(object state)
- {
- this.OnDecompressProgressChanged(state as DecompressProgressChangedEventArgs);
- }
- //解压完成
- private static readonly object EVENT_DECOMPRESS_DATA_COMPLETED = new object();
- /// <summary>
- /// 解压完成事件
- /// </summary>
- public event DecompressDataCompletedEventHandler DecompressDataCompleted
- {
- add { this.Events.AddHandler(EVENT_DECOMPRESS_DATA_COMPLETED, value); }
- remove { this.Events.RemoveHandler(EVENT_DECOMPRESS_DATA_COMPLETED, value); }
- }
- /// <summary>
- /// 触发解压完成事件
- /// </summary>
- /// <param name="e">数据</param>
- protected virtual void OnDecompressDataCompleted(DecompressDataCompletedEventArgs e)
- {
- DecompressDataCompletedEventHandler handler = this.Events[EVENT_DECOMPRESS_DATA_COMPLETED] as DecompressDataCompletedEventHandler;
- if (handler != null)
- handler(this, e);
- }
- /// <summary>
- /// 触发解压完成事件
- /// </summary>
- /// <param name="state">数据</param>
- private void DecompressDataOperationCompleted(object state)
- {
- this.OnDecompressDataCompleted(state as DecompressDataCompletedEventArgs);
- }
- #endregion
- #region 执行回调
- /// <summary>
- /// 执行解压进度报告回调
- /// </summary>
- /// <param name="progress">进度数据</param>
- /// <param name="asyncOp">异步生存期</param>
- private void PostDecompressProgressChanged(ProgressData progress, AsyncOperation asyncOp)
- {
- if (asyncOp == null)
- return;
- int progressPercentage = progress.ToComplete < 0L ? 0 : (progress.ToComplete == 0L ? 100 : (int)(100L * progress.Completed / progress.ToComplete));
- DecompressProgressChangedEventArgs eventArgs = new DecompressProgressChangedEventArgs(progressPercentage, asyncOp.UserSuppliedState);
- this.InvokeOperation(asyncOp, this.m_ReportDecompressProgressChanged, eventArgs);
- }
- /// <summary>
- /// 执行解压数据完成回调
- /// </summary>
- /// <param name="error">错误</param>
- /// <param name="cancelled">是否取消</param>
- /// <param name="asyncOp">异步生存期</param>
- private void DecompressDataAsyncCallback(Exception error, bool cancelled, AsyncOperation asyncOp)
- {
- DecompressDataCompletedEventArgs eventArgs = new DecompressDataCompletedEventArgs(error, cancelled, asyncOp.UserSuppliedState);
- this.InvokeOperationCompleted(asyncOp, this.m_DecompressDataOperationCompleted, eventArgs);
- }
- #endregion
- #region 工作方法
- /// <summary>
- /// 解压数据操作
- /// </summary>
- /// <param name="e">参数</param>
- private void DecompressDataWork(DecompressDataStartArgs e)
- {
- Exception error = null;
- bool cancelled = false;
- try
- {
- using (MemoryStream stream = new MemoryStream(e.Data))
- {
- ReaderOptions readerOptions = new ReaderOptions();
- readerOptions.ArchiveEncoding.Default = Encoding.Default;
- using (IArchive archive = ArchiveFactory.Open(stream, readerOptions))
- {
- this.m_Progress.ToComplete = archive.TotalUncompressSize;
- string deleteEntry = e.DeleteEntry;
- string lastEntry = e.LastEntry;
- string destinationDirectory = e.DestinationDirectory;
- ExtractionOptions extractionOptions = new ExtractionOptions { ExtractFullPath = true, Overwrite = true, PreserveFileTime = true };
- IArchiveEntry last = null;
- foreach (IArchiveEntry entry in archive.Entries)
- {
- if (this.m_Cancelled)
- {
- cancelled = true;
- return;
- }
- if (entry.IsDirectory)
- continue;
- if (last == null && entry.Key.Equals(lastEntry, StringComparison.OrdinalIgnoreCase))
- {
- last = entry;
- continue;
- }
- if (entry.Key.Equals(deleteEntry, StringComparison.OrdinalIgnoreCase))
- DeleteFromDirectory(entry, destinationDirectory, extractionOptions);
- else
- entry.WriteToDirectory(destinationDirectory, extractionOptions);
- this.m_Progress.Completed += entry.Size;
- this.PostDecompressProgressChanged(this.m_Progress, this.m_AsyncOp);
- }
- //保证解压过程的完整性;最后处理可执行exe,保证取消后,下载过程可重现。
- if (last != null)
- {
- if (this.m_Cancelled)
- {
- cancelled = true;
- return;
- }
- if (last.Key.Equals(deleteEntry, StringComparison.OrdinalIgnoreCase))
- DeleteFromDirectory(last, destinationDirectory, extractionOptions);
- else
- last.WriteToDirectory(destinationDirectory, extractionOptions);
- this.m_Progress.Completed += last.Size;
- this.PostDecompressProgressChanged(this.m_Progress, this.m_AsyncOp);
- }
- }
- }
- }
- catch (Exception exp)
- {
- error = exp;
- }
- finally
- {
- this.DecompressDataAsyncCallback(error, cancelled, this.m_AsyncOp);
- }
- }
- /// <summary>
- /// 从目标目录删除压缩文档中的文件列表
- /// </summary>
- /// <param name="entry">压缩文档</param>
- /// <param name="destinationDirectory">目标目录</param>
- /// <param name="options">操作选项</param>
- private void DeleteFromDirectory(IArchiveEntry entry, string destinationDirectory, ExtractionOptions options)
- {
- using (Stream stream = entry.OpenEntryStream())
- {
- using (StreamReader reader = new StreamReader(stream, this.Encoding))
- {
- string file;
- while ((file = reader.ReadLine()) != null)
- {
- file = file.Trim();
- if (file.Length <= 0)
- continue;
- file = Path.Combine(destinationDirectory, options.ExtractFullPath ? file : Path.GetFileName(file));
- if (Directory.Exists(file))
- Directory.Delete(file, true);
- else
- File.Delete(file);
- }
- }
- }
- }
- #endregion
- #region 公共方法
- /// <summary>
- /// 开始异步解压
- /// </summary>
- /// <param name="data">要解压的数据</param>
- /// <param name="deleteEntry">删除列表文件</param>
- /// <param name="lastEntry">最后一个解压的文件</param>
- /// <param name="destinationDirectory">要解压到的目录</param>
- /// <param name="userToken">用户数据</param>
- public void DecompressDataAsync(byte[] data, string deleteEntry, string lastEntry, string destinationDirectory, object userToken = null)
- {
- if (data == null)
- throw new ArgumentNullException("data");
- this.InitAsync();
- this.ClearState();
- AsyncOperation operation = AsyncOperationManager.CreateOperation(userToken);
- this.m_AsyncOp = operation;
- try
- {
- this.m_DecompressDataStart.BeginInvoke(new DecompressDataStartArgs(operation, data, deleteEntry, lastEntry, destinationDirectory), null, null);
- }
- catch (Exception error)
- {
- if (error is ThreadAbortException || error is StackOverflowException || error is OutOfMemoryException)
- throw;
- this.DecompressDataAsyncCallback(error, false, operation);
- }
- }
- #endregion
- }
- }
|