using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using System.Threading;
using System.Collections.Specialized;
using System.Collections;
using System.IO;
using ProjectBase.Data.Zip;
using ProjectBase.Data.Logs;
namespace ProjectBase.Data.Update
{
///
/// 文件复制进度报告事件参数
///
public class FileCopyProgressChangedEventArgs : ProgressChangedEventArgs
{
public FileCopyProgressChangedEventArgs(int progressPercentage, object userState)
: base(progressPercentage, userState)
{
}
///
/// 当前复制的字节数
///
public double BytesToCopy { get; set; }
///
/// 当前复制操作中的字节总数
///
public double TotalBytesToCopy { get; set; }
///
/// 当前复制的源文件名
///
public string SourceFileName { get; set; }
///
/// 当前复制的目标文件名
///
public string TargetFileName { get; set; }
public Manifest Manifest { get; set; }
}
///
/// 文件复制完成事件参数
///
public class FileCopyCompletedEventArgs : AsyncCompletedEventArgs
{
public FileCopyCompletedEventArgs(Exception error, bool cancelled, object userState)
: base(error, cancelled, userState)
{
}
public Manifest Manifest { get; set; }
}
///
/// 文件复制错误事件参数
///
public class FileCopyErrorEventArgs : EventArgs
{
public Exception Error { get; set; }
public Manifest Manifest { get; set; }
}
///
/// 文件复制组件类
///
public class FileCopyClass : Component
{
#region 变量定义
private object defaultTaskId = new object();
private int writeFileLength = 1024 * 64;
private delegate void WorkerEventHandler(Manifest manifest, string sourcePath, AsyncOperation asyncOp);
private SendOrPostCallback onProgressReportDelegate;
private SendOrPostCallback onCompletedDelegate;
private HybridDictionary userStateToLifetime = new HybridDictionary();
private System.ComponentModel.Container components = null;
#endregion
#region 事件
///
/// 文件复制进度事件
///
public event EventHandler FileCopyProgressChanged;
///
/// 文件复制完成事件
///
public event EventHandler FileCopyCompleted;
///
/// 文件复制错误事件
///
public event EventHandler FileCopyError;
#endregion
#region 构造及析构
public FileCopyClass(IContainer container)
{
container.Add(this);
InitializeComponent();
InitializeDelegates();
}
public FileCopyClass()
{
InitializeComponent();
InitializeDelegates();
}
protected virtual void InitializeDelegates()
{
onProgressReportDelegate = new SendOrPostCallback(ReportProgress);
onCompletedDelegate = new SendOrPostCallback(CopyCompleted);
}
private void InitializeComponent()
{
components = new System.ComponentModel.Container();
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose(disposing);
}
#endregion
#region 实现
public int WriteFileLength
{
set
{
writeFileLength = value;
}
}
public void Copy(Manifest manifest, string sourcePath)
{
string[] sourceFiles = null;
string[] targetFiles = null;
GetFiles(manifest, sourcePath, out sourceFiles, out targetFiles);
for (int i = 0; i < sourceFiles.Length; i++)
{
if (!Directory.Exists(Path.GetDirectoryName(targetFiles[i])))
{
Directory.CreateDirectory(Path.GetDirectoryName(targetFiles[i]));
}
File.Copy(sourceFiles[i], targetFiles[i], true);
}
}
public void CopyAsync(Manifest manifest, string sourcePath)
{
CopyAsync(manifest, sourcePath, defaultTaskId);
}
public void CopyAsync(Manifest manifest, string sourcePath, object taskId)
{
AsyncOperation asyncOp = AsyncOperationManager.CreateOperation(taskId);
lock (userStateToLifetime.SyncRoot)
{
if (userStateToLifetime.Contains(taskId))
{
throw new ArgumentException("参数taskId必须是唯一的", "taskId");
}
userStateToLifetime[taskId] = asyncOp;
}
WorkerEventHandler workerDelegate = new WorkerEventHandler(FileCopyWorker);
workerDelegate.BeginInvoke(manifest, sourcePath, asyncOp, null, null);
}
private bool TaskCanceled(object taskId)
{
return (userStateToLifetime[taskId] == null);
}
public void CancelAsync()
{
CancelAsync(defaultTaskId);
}
public void CancelAsync(object taskId)
{
AsyncOperation asyncOp = userStateToLifetime[taskId] as AsyncOperation;
if (asyncOp != null)
{
lock (userStateToLifetime.SyncRoot)
{
userStateToLifetime.Remove(taskId);
}
}
}
private void FileCopyWorker(Manifest manifest, string sourcePath, AsyncOperation asyncOp)
{
Exception exception = null;
FileCopyProgressChangedEventArgs e = null;
Stream rStream = null;
Stream wStream = null;
double writeBytes = 0;
string[] sourceFiles = null;
string[] targetFiles = null;
GetFiles(manifest, sourcePath, out sourceFiles, out targetFiles);
if (!TaskCanceled(asyncOp.UserSuppliedState))
{
try
{
double totalBytes = GetFileLength(sourceFiles);
byte[] buffer = new byte[writeFileLength];
int len = 0;
int offset = 0;
for (int i = 0; i < sourceFiles.Length; i++)
{
try
{
if (!Directory.Exists(Path.GetDirectoryName(targetFiles[i])))
{
Directory.CreateDirectory(Path.GetDirectoryName(targetFiles[i]));
}
rStream = new FileStream(sourceFiles[i], FileMode.Open, FileAccess.Read, FileShare.None);
wStream = new FileStream(targetFiles[i], FileMode.Create, FileAccess.Write, FileShare.None);
while ((len = rStream.Read(buffer, offset, writeFileLength)) > 0)
{
wStream.Write(buffer, offset, len);
writeBytes += len;
e = new FileCopyProgressChangedEventArgs((int)(writeBytes / totalBytes * 100), asyncOp.UserSuppliedState);
e.SourceFileName = sourceFiles[i];
e.TargetFileName = targetFiles[i];
e.TotalBytesToCopy = totalBytes;
e.BytesToCopy += writeBytes;
e.Manifest = manifest;
asyncOp.Post(this.onProgressReportDelegate, e);
Thread.Sleep(1);
}
}
finally
{
DisposeStream(wStream);
DisposeStream(rStream);
}
}
}
catch (Exception ex)
{
exception = ex;
OnFileCopyError(new FileCopyErrorEventArgs() { Error = ex, Manifest = manifest });
}
}
this.CompletionMethod(manifest, exception, TaskCanceled(asyncOp.UserSuppliedState), asyncOp);
//如果文件是压缩文件,则解压这些文件
ZipFiles(e.Manifest);
}
private void GetFiles(Manifest manifest, string sourcePath,out string[] sourceFiles,out string[] targetFiles)
{
sourceFiles = new string[manifest.ManifestFiles.Files.Length];
targetFiles = new string[manifest.ManifestFiles.Files.Length];
string path = Path.GetFullPath(manifest.MyApplication.Location);
for (int i = 0; i < manifest.ManifestFiles.Files.Length; i++)
{
sourceFiles[i] = Path.Combine(sourcePath, manifest.ManifestFiles.Files[i].Source);
targetFiles[i] = Path.Combine(path, manifest.ManifestFiles.Files[i].Source);
}
}
private void DisposeStream(Stream stream)
{
if (stream != null)
{
stream.Flush();
stream.Close();
stream.Dispose();
}
}
private double GetFileLength(string[] sourceFiles)
{
double bytes = 0;
foreach (var file in sourceFiles)
{
FileInfo fileInfo = new FileInfo(file);
bytes += fileInfo.Length;
}
return bytes;
}
private void CopyCompleted(object operationState)
{
FileCopyCompletedEventArgs e = operationState as FileCopyCompletedEventArgs;
OnFileCopyCompleted(e);
}
private void ReportProgress(object state)
{
FileCopyProgressChangedEventArgs e = state as FileCopyProgressChangedEventArgs;
OnProgressChanged(e);
}
protected void OnFileCopyCompleted(FileCopyCompletedEventArgs e)
{
if (FileCopyCompleted != null)
{
FileCopyCompleted(this, e);
}
}
///
/// 如果文件是压缩文件,则解压这些文件
///
///
private void ZipFiles(Manifest manifest)
{
if (manifest != null)
{
string path = Path.GetFullPath(manifest.MyApplication.Location);
foreach (ManifestFile file in manifest.ManifestFiles.Files)
{
bool unzip = false;
bool.TryParse(file.Unzip, out unzip);
if (file.Source.EndsWith(".zip", StringComparison.OrdinalIgnoreCase) && unzip)
{
string zipFile = Path.Combine(path, file.Source);
try
{
ZipUtility.UnZipFiles(zipFile, path, null, true);
}
catch (Exception ex)
{
LogHelper.log.Error("解压文件出现错误" + ex);
}
}
}
}
}
//public static void WriteLine(string message)
//{
// string temp = DateTime.Now.ToString("[yyyy-MM-dd HH:mm:ss] ") + message + "\r\n\r\n";
// string fileName = DateTime.Now.ToString("yyyyMMdd") + ".log";
// try
// {
// File.AppendAllText(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, fileName), temp, Encoding.GetEncoding("GB2312"));
// }
// catch (Exception ex)
// {
// LogHelper.log.Error();
// }
//}
protected void OnProgressChanged(FileCopyProgressChangedEventArgs e)
{
if (FileCopyProgressChanged != null)
{
FileCopyProgressChanged(this, e);
}
}
protected void OnFileCopyError(FileCopyErrorEventArgs e)
{
if (FileCopyError != null)
{
FileCopyError(this, e);
}
}
private void CompletionMethod(Manifest manifest, Exception exception, bool canceled, AsyncOperation asyncOp)
{
if (!canceled)
{
lock (userStateToLifetime.SyncRoot)
{
userStateToLifetime.Remove(asyncOp.UserSuppliedState);
}
}
FileCopyCompletedEventArgs e = new FileCopyCompletedEventArgs(exception, canceled, asyncOp.UserSuppliedState);
e.Manifest = manifest;
asyncOp.PostOperationCompleted(onCompletedDelegate, e);
}
#endregion
}
}