1. 程式人生 > >非同步程式設計-非同步讀取檔案

非同步程式設計-非同步讀取檔案

這篇文章我們學習如何用非同步程式設計來讀取檔案。

使用System.IO.Stream類的非同步呼叫方法,對檔案out.txt進行非同步讀操作。

執行結果:

原始碼:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Runtime.Remoting.Contexts;
using System.IO;

namespace Test1_1
{
    class HelloWorld
    {
        static void Main(string[] args)
        {
            //例項化非同步I/O測試器
            AsynchIOTester theApp = new AsynchIOTester("D:\\out.txt");
            //建立回撥委託物件
            AsyncCallback myCallBack = new AsyncCallback(OnReadDone);
            //開始非同步讀操作
            IAsyncResult ar = theApp.InputStream.BeginRead(
                theApp.Buffer,                                                      //存放結果的快取
                0,                                                                  //偏移值
                theApp.Buffer.Length,                                               //緩衝大小
                myCallBack,                                                         //回撥方法
                theApp);                                                            //區域性狀態物件
            Console.WriteLine("++++++主執行緒繼續工作+++++");
            Thread.Sleep(1000);
            Console.WriteLine("\n\n++++++++主執行緒工作完成,執行了1秒,等待非同步呼叫完成\n");

            Console.Read();
        }
        //回撥方法
        static void OnReadDone(IAsyncResult ar)
        {
            //獲取區域性狀態物件
            AsynchIOTester test = (AsynchIOTester)ar.AsyncState; 
            //結束非同步讀操作,返回讀取的位元組數
            int bufferCount = test.InputStream.EndRead(ar);

            if (bufferCount > 0)
            {
                //模擬下一次讀取間隔0.1s,以免較快讀完
                Thread.Sleep(100);
                //轉換成指對編碼的字串
                string s = Encoding.GetEncoding("GB2312").GetString(test.Buffer, 0, bufferCount);
                Console.Write(s);
                //建立回撥委託物件
                AsyncCallback myCallBack = new AsyncCallback(OnReadDone);
                //如果沒有讀完,再次非同步呼叫BeginRead
                test.InputStream.BeginRead(test.Buffer, 0, test.Buffer.Length, myCallBack, test);
            }
        }
    }
    //非同步I/O測試器
    public class AsynchIOTester
    {
        private Stream inputStream;                         //輸入流
        private byte[] buffer;                              //存入讀入資料的緩衝區
        private string filename;

        public AsynchIOTester(string filename)              //建構函式
        {
            this.filename = filename;
            inputStream = File.OpenRead(filename);          //開啟檔案
            buffer = new byte[16];                          //分配緩衝
        }

        public byte[] Buffer
        {
            get { return buffer; }
        }

        public Stream InputStream
        {
            get { return inputStream ;}
        }
    }
}

主執行緒首先建立了一個AsynchIOTester非同步I/O測試器物件(即theApp)。該物件包括輸入流,緩衝區等資訊。程式可以在回撥時獲取它。然後,主執行緒中聲明瞭一個AsyncCallBack型別的委託物件myCallback,用於建立回撥委託物件。該物件綁定了回撥方法OnReadDone()。接下來,呼叫BeginRead()方法,進行檔案的非同步讀取,之後我們使用Thread.Sleep(1000)來模擬需要執行的操作耗時1秒。這時,非同步呼叫已經開始,因為不希望一次非同步呼叫就讀完整個檔案,因此,將緩衝區設為16個位元組。

當讀取完成時,CLR將呼叫回撥方法OnReadDone()。在OnReadDone()方法中,我們首先用(AsynchIOTester)ar.AsyncState獲取呼叫開始時封裝的非同步I/O數。如果位元組數大於0,將緩衝轉換成字串並輸出,然後再次呼叫BeginRead,開始下一次非同步讀取,為避免因為較快讀完,而無法驗證是否進行了非同步呼叫,我們使用Thread.Sleep(100),使之在0.1秒後再進行下一個操作。