PDA

View Full Version : آموزش: برنامه نویسی اسنکرون در FileStream



silsin
پنج شنبه 07 خرداد 1394, 11:16 صبح
قبل از شروع بهتره یه توضیح مختصری در مورد فرق سنکرون و اسنکرون بدم این رو در قالب یه مثال توضیح میدم که راحت تر متوجه بشین .
فرض کنید مثلا سناریو ما پیاده سازی یک برنامه کلاینت سروری .
اول از همه حالت سنکرون :
مراحل به این صورت پیاده سازی می شن
ابتدا سرور راه اندازی میشه - کلاینت درخواست اتصال به سرور رو می فرسته حالا نکته اصلی اینجاست اگر به هر دلیلی این درخواست فرستادن بازگشتی نداشته باشه با توجه به سبک برنامه نویسی سنکرونی که توش به کار رفته کلاینت تا زمانی که سرور تاییده اتصال رو بهش نده به اصطلاح در حالت Halt باقی خواهد موند حالا فرض کنین به جای یک کلاینت ده تا یا صد تا یا هزار تا داشته باشین که دیگه فاجعه میشه!
همینطور زمانی که می خواین پیغام رو بفرستین به طرف مقابل باز هم همین مشکل Halt َدن پیش میاد .
مثال دیگه ای از همین فایل استریمه . زمانی که می خواین فایلی رو به اصطلاح Read کنین باز هم همین مشکل پیش میاد ! اگر فایل شما تا 64 kb یا همین حدودها باشه مشکلی پیش نمیاد اما اگه بیشتر بشه برنامه تا زمانی که عمل Read به طور کامل انجام بشه باز هم به صورت Halt در میاد !!! اما چاره چیه ؟ در ادامه حالتی که اسنکرون نام داره رو بررسی خواهیم کرد .
حالت اسنکرون :
یک جا خونده بودم مثال جالبی برای توضیح دادنش زده بود.
بر پایه همون مثال قبلیمون
ابتدا سرور راه اندازی میشه - کلاینت اتصال به سرور می فرسته اما برعکس حالت قبلی برنامه صبر نمی کنه که مجوز اتصالش صادر بشه بلکه برنامه به کار خودش ادامه میده فقط زمانی که پاسخ اومد کار رو انجام میده (نمیدونم منظورم رو خوب رسوندم یا نه ) حالا در مورد برنامه های بزرگ این واقعا بهشته مطلقه :D این توضیح در مورد Read کردن فایل ها هم جوا ب میده و دیگه اون مشکل قبلی پیش نمیاد .
توی این مثالی که می خوام بزنم برنامه نویسی اسنکرون رو تو FileStream تست می کنیم .

- پروژه جدیدی ایجاد کنید
-- ابزاری که باید ازشون استفاده کنیم شامل :
OpenFileDialog
یک Button
یک TextBox برای نمایش نتیجه

مسلما زمانی که صحبت از FileStream شد پس مسلما کتابخونه System.IO باید استفاده بشه
متغییر های زیر رو تعریف کنید
FileStream Fs
این متغییر رو برای دسترسی به کلاس های فایل از کتابخونه System.IO
دو متغییر دیگه هم با نام های :

byte[] fileContents;
AsyncCallback callback;
بر روی Button کلیک کنید
اول از همه پنجره OpenFileDialog رو باز می کنیم :

openFileDialog.ShowDialog();

به وسیله این کد زمانی که بر روی Button کلیک کنیم پنجره مربوطه باز خواهد شد
در خط بعد باید CallBack حاصل از عمل اسنکرونی که انجام میشه رو تعریف کنیم .
لازمه که این رو توضیح بدم :
مسلما زمانی که عملی انجام میشه خروجی هم خواهد داشت . به عنوان مثال . ایا تکمیل شده ؟ ایا شکست خورده ؟؟ یا در چه مرحله ای قرار داره ؟
تمامی این ها رو با نام CallBack یا همون بازگشتی خواهیم شناخت . و برای این کار هم ما باید متد بازگشتی رو داشته باشیم
ابتدا رویداد بازگشتی مربوطه رو تعریف میک نیم
callback = new AsyncCallback(fs_StateChanged);
در خط بعد ویژگی مربوط به OpenFileDialog خودمون رو تعریف می کنیم
fs = new FileStream(openFileDialog.FileName, FileMode.Open,
FileAccess.Read, FileShare.Read, 4096, true);
در خط بعد ورودی رو به صورت Byte دریافت می کنیم
fileContents = new Byte[fs.Length];
نکته اصلی خط بعده

fs.BeginRead(fileContents, 0, (int)fs.Length, callback,
null);

در اینجا می تونیم اینجوری هم بگیم که شروع به خوندن می کنه نه اینکه بخواد بخونه ! مسلما اگه با فایل دیالوگ کار کرده باشین می دین پارامترهاش چی هستن .البته دوتا پارامتر اضافه داره که توضیح میدم
ابتدا CallBack
این همون متغییر CallBack که بالا تعریف کردیم که نقش Event بازگشتی ما رو برعهده داره
می تونین حتی اون تعریف بالا رو هم نداشته باشین و مستقیما با New کردن EventCallBack ازش استفاده کنین
اخرین پارامتر به کار رفته هم در حقیقت میشه گفت object ایه که قراره کار بر روی اون انجام بشه یا بهتره بگیم Object ایه که قراره درخواست روی اون انجام بشه
بعد از تعریف لازمه حالا تابع بازگشتی خودمون رو تعریف کنیم

private void fs_StateChanged(IAsyncResult asyncResult)
{
if (asyncResult.IsCompleted)
{
tbResults.Text = Encoding.UTF8.GetString(fileContents);
fs.Close();
}
}

همینطور که می بینید زمانی که عمل خوندن کامل شد اون موقع میاد نتیجه رو در تکست باکس ما قرار میده و بعد از اون فایل استریم رو می بنده
البته نکته اصلی که باید دقت کنید اینه که زمانی که کار تکمیل شد خوندن هم باید تکمیل بشه پس این تکه کد رو هم اضافه کنید
fs.EndRead(result);

اما یک نکته مهم زمانی که می خواین برنامه اجرا و استفاده کنین خواهید دید که به شما هشدار میده و اجازه استفاده رو نمیده
در حقیقت زمانی که شما دارین از تکست باکس استفاده می کنین به این شیوه بخوام ساده تر بگم تسکست باکس شما به وسیله ترد UI داره اجرا میشه و شما به وسیله متدی که نوشتین در حقیقت اون رو به ترد جدیدی می برین واسه همین می نویسه Cross theread Not Valid راه حل این مشکل خیلی ساده است
https://msdn.microsoft.com/en-us/library/ms171728.aspx
البته بهتره بگیم این یک ویژگیه که باعث میشه مشکلی در اجرا ترد ها به وجود نیاد یه جورایی میشه گفت کاری می کنه که تداخل یا به قول خودش باگی به وجود نیاد
اما برای رفع این مشکل ما این کار رو می کنیم :


delegate void SetTextCallBack(string text);


private void SetText(string text)
{

if (this.tbResult.InvokeRequired)
{
SetTextCallBack d = new SetTextCallBack(SetText);
this.Invoke(d, new object[] { text });

}
else
{
this.tbResult.Text = text;
}

}



حالا می تونید برنامه رو اجرا و نتیجه ر و مشاهده کنید
به همین راحتی
کد کامل :

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
namespace Async_1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
FileStream fs;
AsyncCallback callBack;
byte[] Contents;

private void btnReadAsync_Click(object sender, EventArgs e)
{
openFileDialog1.ShowDialog();

fs = new FileStream(openFileDialog1.FileName, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, true);
Contents = new Byte[fs.Length];
fs.BeginRead(Contents,0,(int)fs.Length,new AsyncCallback(Fs_stateChange),fs);
}

delegate void SetTextCallBack(string text);


private void SetText(string text)
{

if (this.tbResult.InvokeRequired)
{
SetTextCallBack d = new SetTextCallBack(SetText);
this.Invoke(d, new object[] { text });

}
else
{
this.tbResult.Text = text;
}

}


private void Fs_stateChange(IAsyncResult result)
{
if (result.IsCompleted)
{

fs.EndRead(result);
SetText(ASCIIEncoding.ASCII.GetString(Contents));


fs.Close();
}
}
}
}




امیدوارم به کارتون بیاد
موفق باشید