using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Threading;
using System.ComponentModel;
namespace ExtensionTest
{
public class Async : IDisposable
{
private bool suspend;
private bool cancel;
private Stream readStream;
private Stream writeSteam;
private AutoResetEvent auto;
public long TotalLength { get; private set; }
private AsyncOperation asyncOperation;
public bool Suspend
{
get { return this.suspend; }
set
{
if (this.suspend && !value && !this.auto.SafeWaitHandle.IsClosed)
auto.Set();
this.suspend = value;
}
}
public bool Cancel
{
get { return cancel; }
set { cancel = value; }
}
public event EventHandler<ReportEventArgs> ProgressReport;
public Async()
{
asyncOperation = AsyncOperationManager.CreateOperation(null);
auto = new AutoResetEvent(true);
}
/// <summary>
/// 初始化读写流
/// </summary>
/// <param name="fileToRead">用来读取的文件名</param>
/// <param name="fileToWrite">用来保存的文件名</param>
private void InitStream(string fileToRead, string fileToWrite)
{
if (!File.Exists(fileToRead))
{
throw new ArgumentException();
}
FileInfo info = new FileInfo(fileToRead);
//文件大小
this.TotalLength = info.Length;
/*
* 根据文件大小选择选择读取和写入文件的策略
* 如果大于某个值就构造异步流
*/
//if (info.Length > 10 * 1024 * 1024)
//{
// readStream = new FileStream(fileToRead, FileMode.Open, FileAccess.Read, FileShare.Read, 1024,
// FileOptions.Asynchronous);
//}
//else
readStream = info.Open(FileMode.Open, FileAccess.Read, FileShare.Read);
writeSteam = File.Open(fileToWrite, FileMode.Create, FileAccess.Write, FileShare.Write);
}
/// <summary>
/// 使用迭代器开始异步操作
/// </summary>
/// <param name="fileToRead">用来读取的文件名</param>
/// <param name="fileToWrite">用来保存的文件名</param>
public void StartAsyncOperationWithIterator(string fileToRead, string fileToWrite)
{
this.InitStream(fileToRead, fileToWrite);
ThreadPool.QueueUserWorkItem(arg =>
{
byte[] buffer = new byte[1024];
IEnumerator<int> enumerator = ReadBytes(buffer);
while (enumerator.MoveNext())
{
if (this.suspend && !auto.SafeWaitHandle.IsClosed)
auto.WaitOne();
this.asyncOperation.Post(obj => this.OnReportProgress(enumerator.Current), null);
/*
*如果是Thread.Sleep(0)由于消息发送太快 接收进度报告的窗体也呈假死状态
* 而如果是Thread.Sleep(1)则会影响读写速度 惆怅
*/
Thread.Sleep(1);
}
});
}
private IEnumerator<int> ReadBytes(byte[] buffer)
{
try
{
int readLength = readStream.Read(buffer, 0, buffer.Length);
while (readLength > 0)
{
writeSteam.Write(buffer, 0, readLength);
yield return readLength;
if (this.cancel)
{
this.Dispose();
yield break;
}
readLength = readStream.Read(buffer, 0, buffer.Length);
}
}
finally
{
this.Dispose();
}
}
/// <summary>
/// 开始异步操作
/// </summary>
/// <param name="fileToRead">用来读取的文件名</param>
/// <param name="fileToWrite">用来保存的文件名</param>
public void StartAsyncOperation(string fileToRead, string fileToWrite)
{
this.StartAsyncOperation(fileToRead, fileToWrite, null);
}
/// <summary>
/// 开始异步操作
/// </summary>
/// <param name="fileToRead">用来读取的文件名</param>
/// <param name="fileToWrite">用来保存的文件名</param>
/// <param name="completed">完成读写操作后的回调方法</param>
public void StartAsyncOperation(string fileToRead, string fileToWrite, Action<Exception> completed)
{
this.StartAsyncOperation(fileToRead, fileToWrite, null, completed);
}
/// <summary>
/// 开始异步操作
/// </summary>
/// <param name="fileToRead">用来读取的文件名</param>
/// <param name="fileToWrite">用来保存的文件名</param>
/// <param name="cancelAction">取消时的回调方法</param>
/// <param name="completed">完成读写操作后的回调方法</param>
public void StartAsyncOperation(string fileToRead, string fileToWrite, Action cancelAction, Action<Exception> completed)
{
this.StartAsyncOperation(fileToRead, fileToWrite, null, cancelAction, completed);
}
/// <summary>
/// 开始异步操作
/// </summary>
/// <param name="fileToRead">用来读取的文件名</param>
/// <param name="fileToWrite">用来保存的文件名</param>
/// <param name="suspendAction">暂停时的回调方法</param>
/// <param name="cancelAction">取消时的回调方法</param>
/// <param name="completed">完成读写操作后的回调方法</param>
public void StartAsyncOperation(string fileToRead, string fileToWrite, Action<bool> suspendAction, Action cancelAction, Action<Exception> completed)
{
this.StartAsyncOperation(fileToRead, fileToWrite, null, suspendAction, cancelAction, completed);
}
/// <summary>
/// 开始异步操作
/// </summary>
/// <param name="fileToRead">用来读取的文件名</param>
/// <param name="fileToWrite">用来保存的文件名</param>
/// <param name="timeOutAction">超时时调用的方法(只有支持超时的流才会回调)</param>
/// <param name="suspendAction">暂停时的回调方法</param>
/// <param name="cancelAction">取消时的回调方法</param>
/// <param name="completed">完成读写操作后的回调方法</param>
public void StartAsyncOperation(string fileToRead, string fileToWrite, Action<Operation> timeOutAction, Action<bool> suspendAction, Action cancelAction, Action<Exception> completed)
{
this.InitStream(fileToRead, fileToWrite);
if (readStream == null || writeSteam == null) return;
byte[] buffer = new byte[1024];
AsyncCallback callback = null;
callback = readResult =>
{
int readLength = readStream.EndRead(readResult);
if (readLength > 0)
{
writeSteam.BeginWrite(buffer, 0, readLength, writeResult =>
{
try
{
writeSteam.EndWrite(writeResult);
//降低cpu使用率
Thread.Sleep(0);
OnReportProgress(readLength);
//暂停
if (this.suspend && !this.auto.SafeWaitHandle.IsClosed)
{
if (suspendAction != null)
suspendAction(true);
this.auto.WaitOne();
}
//取消
if (cancel)
{
this.Dispose();
if (cancelAction != null)
asyncOperation.Post(obj => cancelAction(), null);
return;
}
readStream.BeginRead(buffer, 0, buffer.Length, callback, null);
}
catch (Exception ex)
{
Dispose();
if (completed != null)
asyncOperation.Post(obj => completed(ex), null);
}
}, null);
}
else
{
Dispose();
if (completed != null)
asyncOperation.Post(obj => completed(null), null);
}
};
readStream.BeginRead(buffer, 0, buffer.Length, callback, null);
}
private void Dispose()
{
readStream.Close();
readStream.Dispose();
writeSteam.Close();
writeSteam.Dispose();
}
private void OnReportProgress(int readLength)
{
if (this.ProgressReport != null)
{
ReportEventArgs args = new ReportEventArgs(readLength, this.TotalLength);
//发送完成进度报告
asyncOperation.Post(obj => this.ProgressReport(null, args), null);
}
}
void IDisposable.Dispose()
{
auto.Close();
}
}
public enum Operation
{
Read,
Write
}
public class ReportEventArgs : EventArgs
{
public long CompletedLength { get; private set; }
public long TotalLength { get; private set; }
public ReportEventArgs(long completedLength, long totalLength)
{
this.CompletedLength = completedLength;
this.TotalLength = totalLength;
}
}
}