实现文件异步读写、暂停、继续、停止功能的类

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;
        }
    }
}
posted @ 2009-07-02 22:31  非空  阅读(1664)  评论(2编辑  收藏  举报