FileCopyClass.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using System.ComponentModel;
  5. using System.Threading;
  6. using System.Collections.Specialized;
  7. using System.Collections;
  8. using System.IO;
  9. using ProjectBase.Data.Zip;
  10. using ProjectBase.Data.Logs;
  11. namespace ProjectBase.Data.Update
  12. {
  13. /// <summary>
  14. /// 文件复制进度报告事件参数
  15. /// </summary>
  16. public class FileCopyProgressChangedEventArgs : ProgressChangedEventArgs
  17. {
  18. public FileCopyProgressChangedEventArgs(int progressPercentage, object userState)
  19. : base(progressPercentage, userState)
  20. {
  21. }
  22. /// <summary>
  23. /// 当前复制的字节数
  24. /// </summary>
  25. public double BytesToCopy { get; set; }
  26. /// <summary>
  27. /// 当前复制操作中的字节总数
  28. /// </summary>
  29. public double TotalBytesToCopy { get; set; }
  30. /// <summary>
  31. /// 当前复制的源文件名
  32. /// </summary>
  33. public string SourceFileName { get; set; }
  34. /// <summary>
  35. /// 当前复制的目标文件名
  36. /// </summary>
  37. public string TargetFileName { get; set; }
  38. public Manifest Manifest { get; set; }
  39. }
  40. /// <summary>
  41. /// 文件复制完成事件参数
  42. /// </summary>
  43. public class FileCopyCompletedEventArgs : AsyncCompletedEventArgs
  44. {
  45. public FileCopyCompletedEventArgs(Exception error, bool cancelled, object userState)
  46. : base(error, cancelled, userState)
  47. {
  48. }
  49. public Manifest Manifest { get; set; }
  50. }
  51. /// <summary>
  52. /// 文件复制错误事件参数
  53. /// </summary>
  54. public class FileCopyErrorEventArgs : EventArgs
  55. {
  56. public Exception Error { get; set; }
  57. public Manifest Manifest { get; set; }
  58. }
  59. /// <summary>
  60. /// 文件复制组件类
  61. /// </summary>
  62. public class FileCopyClass : Component
  63. {
  64. #region 变量定义
  65. private object defaultTaskId = new object();
  66. private int writeFileLength = 1024 * 64;
  67. private delegate void WorkerEventHandler(Manifest manifest, string sourcePath, AsyncOperation asyncOp);
  68. private SendOrPostCallback onProgressReportDelegate;
  69. private SendOrPostCallback onCompletedDelegate;
  70. private HybridDictionary userStateToLifetime = new HybridDictionary();
  71. private System.ComponentModel.Container components = null;
  72. #endregion
  73. #region 事件
  74. /// <summary>
  75. /// 文件复制进度事件
  76. /// </summary>
  77. public event EventHandler<FileCopyProgressChangedEventArgs> FileCopyProgressChanged;
  78. /// <summary>
  79. /// 文件复制完成事件
  80. /// </summary>
  81. public event EventHandler<FileCopyCompletedEventArgs> FileCopyCompleted;
  82. /// <summary>
  83. /// 文件复制错误事件
  84. /// </summary>
  85. public event EventHandler<FileCopyErrorEventArgs> FileCopyError;
  86. #endregion
  87. #region 构造及析构
  88. public FileCopyClass(IContainer container)
  89. {
  90. container.Add(this);
  91. InitializeComponent();
  92. InitializeDelegates();
  93. }
  94. public FileCopyClass()
  95. {
  96. InitializeComponent();
  97. InitializeDelegates();
  98. }
  99. protected virtual void InitializeDelegates()
  100. {
  101. onProgressReportDelegate = new SendOrPostCallback(ReportProgress);
  102. onCompletedDelegate = new SendOrPostCallback(CopyCompleted);
  103. }
  104. private void InitializeComponent()
  105. {
  106. components = new System.ComponentModel.Container();
  107. }
  108. protected override void Dispose(bool disposing)
  109. {
  110. if (disposing)
  111. {
  112. if (components != null)
  113. {
  114. components.Dispose();
  115. }
  116. }
  117. base.Dispose(disposing);
  118. }
  119. #endregion
  120. #region 实现
  121. public int WriteFileLength
  122. {
  123. set
  124. {
  125. writeFileLength = value;
  126. }
  127. }
  128. public void Copy(Manifest manifest, string sourcePath)
  129. {
  130. string[] sourceFiles = null;
  131. string[] targetFiles = null;
  132. GetFiles(manifest, sourcePath, out sourceFiles, out targetFiles);
  133. for (int i = 0; i < sourceFiles.Length; i++)
  134. {
  135. if (!Directory.Exists(Path.GetDirectoryName(targetFiles[i])))
  136. {
  137. Directory.CreateDirectory(Path.GetDirectoryName(targetFiles[i]));
  138. }
  139. File.Copy(sourceFiles[i], targetFiles[i], true);
  140. }
  141. }
  142. public void CopyAsync(Manifest manifest, string sourcePath)
  143. {
  144. CopyAsync(manifest, sourcePath, defaultTaskId);
  145. }
  146. public void CopyAsync(Manifest manifest, string sourcePath, object taskId)
  147. {
  148. AsyncOperation asyncOp = AsyncOperationManager.CreateOperation(taskId);
  149. lock (userStateToLifetime.SyncRoot)
  150. {
  151. if (userStateToLifetime.Contains(taskId))
  152. {
  153. throw new ArgumentException("参数taskId必须是唯一的", "taskId");
  154. }
  155. userStateToLifetime[taskId] = asyncOp;
  156. }
  157. WorkerEventHandler workerDelegate = new WorkerEventHandler(FileCopyWorker);
  158. workerDelegate.BeginInvoke(manifest, sourcePath, asyncOp, null, null);
  159. }
  160. private bool TaskCanceled(object taskId)
  161. {
  162. return (userStateToLifetime[taskId] == null);
  163. }
  164. public void CancelAsync()
  165. {
  166. CancelAsync(defaultTaskId);
  167. }
  168. public void CancelAsync(object taskId)
  169. {
  170. AsyncOperation asyncOp = userStateToLifetime[taskId] as AsyncOperation;
  171. if (asyncOp != null)
  172. {
  173. lock (userStateToLifetime.SyncRoot)
  174. {
  175. userStateToLifetime.Remove(taskId);
  176. }
  177. }
  178. }
  179. private void FileCopyWorker(Manifest manifest, string sourcePath, AsyncOperation asyncOp)
  180. {
  181. Exception exception = null;
  182. FileCopyProgressChangedEventArgs e = null;
  183. Stream rStream = null;
  184. Stream wStream = null;
  185. double writeBytes = 0;
  186. string[] sourceFiles = null;
  187. string[] targetFiles = null;
  188. GetFiles(manifest, sourcePath, out sourceFiles, out targetFiles);
  189. if (!TaskCanceled(asyncOp.UserSuppliedState))
  190. {
  191. try
  192. {
  193. double totalBytes = GetFileLength(sourceFiles);
  194. byte[] buffer = new byte[writeFileLength];
  195. int len = 0;
  196. int offset = 0;
  197. for (int i = 0; i < sourceFiles.Length; i++)
  198. {
  199. try
  200. {
  201. if (!Directory.Exists(Path.GetDirectoryName(targetFiles[i])))
  202. {
  203. Directory.CreateDirectory(Path.GetDirectoryName(targetFiles[i]));
  204. }
  205. rStream = new FileStream(sourceFiles[i], FileMode.Open, FileAccess.Read, FileShare.None);
  206. wStream = new FileStream(targetFiles[i], FileMode.Create, FileAccess.Write, FileShare.None);
  207. while ((len = rStream.Read(buffer, offset, writeFileLength)) > 0)
  208. {
  209. wStream.Write(buffer, offset, len);
  210. writeBytes += len;
  211. e = new FileCopyProgressChangedEventArgs((int)(writeBytes / totalBytes * 100), asyncOp.UserSuppliedState);
  212. e.SourceFileName = sourceFiles[i];
  213. e.TargetFileName = targetFiles[i];
  214. e.TotalBytesToCopy = totalBytes;
  215. e.BytesToCopy += writeBytes;
  216. e.Manifest = manifest;
  217. asyncOp.Post(this.onProgressReportDelegate, e);
  218. Thread.Sleep(1);
  219. }
  220. }
  221. finally
  222. {
  223. DisposeStream(wStream);
  224. DisposeStream(rStream);
  225. }
  226. }
  227. }
  228. catch (Exception ex)
  229. {
  230. exception = ex;
  231. OnFileCopyError(new FileCopyErrorEventArgs() { Error = ex, Manifest = manifest });
  232. }
  233. }
  234. this.CompletionMethod(manifest, exception, TaskCanceled(asyncOp.UserSuppliedState), asyncOp);
  235. //如果文件是压缩文件,则解压这些文件
  236. ZipFiles(e.Manifest);
  237. }
  238. private void GetFiles(Manifest manifest, string sourcePath,out string[] sourceFiles,out string[] targetFiles)
  239. {
  240. sourceFiles = new string[manifest.ManifestFiles.Files.Length];
  241. targetFiles = new string[manifest.ManifestFiles.Files.Length];
  242. string path = Path.GetFullPath(manifest.MyApplication.Location);
  243. for (int i = 0; i < manifest.ManifestFiles.Files.Length; i++)
  244. {
  245. sourceFiles[i] = Path.Combine(sourcePath, manifest.ManifestFiles.Files[i].Source);
  246. targetFiles[i] = Path.Combine(path, manifest.ManifestFiles.Files[i].Source);
  247. }
  248. }
  249. private void DisposeStream(Stream stream)
  250. {
  251. if (stream != null)
  252. {
  253. stream.Flush();
  254. stream.Close();
  255. stream.Dispose();
  256. }
  257. }
  258. private double GetFileLength(string[] sourceFiles)
  259. {
  260. double bytes = 0;
  261. foreach (var file in sourceFiles)
  262. {
  263. FileInfo fileInfo = new FileInfo(file);
  264. bytes += fileInfo.Length;
  265. }
  266. return bytes;
  267. }
  268. private void CopyCompleted(object operationState)
  269. {
  270. FileCopyCompletedEventArgs e = operationState as FileCopyCompletedEventArgs;
  271. OnFileCopyCompleted(e);
  272. }
  273. private void ReportProgress(object state)
  274. {
  275. FileCopyProgressChangedEventArgs e = state as FileCopyProgressChangedEventArgs;
  276. OnProgressChanged(e);
  277. }
  278. protected void OnFileCopyCompleted(FileCopyCompletedEventArgs e)
  279. {
  280. if (FileCopyCompleted != null)
  281. {
  282. FileCopyCompleted(this, e);
  283. }
  284. }
  285. /// <summary>
  286. /// 如果文件是压缩文件,则解压这些文件
  287. /// </summary>
  288. /// <param name="manifest"></param>
  289. private void ZipFiles(Manifest manifest)
  290. {
  291. if (manifest != null)
  292. {
  293. string path = Path.GetFullPath(manifest.MyApplication.Location);
  294. foreach (ManifestFile file in manifest.ManifestFiles.Files)
  295. {
  296. bool unzip = false;
  297. bool.TryParse(file.Unzip, out unzip);
  298. if (file.Source.EndsWith(".zip", StringComparison.OrdinalIgnoreCase) && unzip)
  299. {
  300. string zipFile = Path.Combine(path, file.Source);
  301. try
  302. {
  303. ZipUtility.UnZipFiles(zipFile, path, null, true);
  304. }
  305. catch (Exception ex)
  306. {
  307. LogHelper.log.Error("解压文件出现错误" + ex);
  308. }
  309. }
  310. }
  311. }
  312. }
  313. //public static void WriteLine(string message)
  314. //{
  315. // string temp = DateTime.Now.ToString("[yyyy-MM-dd HH:mm:ss] ") + message + "\r\n\r\n";
  316. // string fileName = DateTime.Now.ToString("yyyyMMdd") + ".log";
  317. // try
  318. // {
  319. // File.AppendAllText(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, fileName), temp, Encoding.GetEncoding("GB2312"));
  320. // }
  321. // catch (Exception ex)
  322. // {
  323. // LogHelper.log.Error();
  324. // }
  325. //}
  326. protected void OnProgressChanged(FileCopyProgressChangedEventArgs e)
  327. {
  328. if (FileCopyProgressChanged != null)
  329. {
  330. FileCopyProgressChanged(this, e);
  331. }
  332. }
  333. protected void OnFileCopyError(FileCopyErrorEventArgs e)
  334. {
  335. if (FileCopyError != null)
  336. {
  337. FileCopyError(this, e);
  338. }
  339. }
  340. private void CompletionMethod(Manifest manifest, Exception exception, bool canceled, AsyncOperation asyncOp)
  341. {
  342. if (!canceled)
  343. {
  344. lock (userStateToLifetime.SyncRoot)
  345. {
  346. userStateToLifetime.Remove(asyncOp.UserSuppliedState);
  347. }
  348. }
  349. FileCopyCompletedEventArgs e = new FileCopyCompletedEventArgs(exception, canceled, asyncOp.UserSuppliedState);
  350. e.Manifest = manifest;
  351. asyncOp.PostOperationCompleted(onCompletedDelegate, e);
  352. }
  353. #endregion
  354. }
  355. }