05-10-12, 01:38 AM
كاتب الموضوع : samerselo
توفر لك الأداة FileSystemWatcher إمكانية مراقبة مجلد أو شجرة مجلدات بحيث تحصل على تنبيهات عندما يحصل أي شئ بداخلها فمثلا عندما يتم إنشاء أو حذف أو إعادة تسمية مجلد أو ملف أو عندما تتغير خصائص مجلد ما حيث تعتبر هذه الأداة ذات فائدة في العديد من الظروف فإذا كنت تقوم بعمل برنامج يقوم بتشفير الملفات آليا عندما يتم تخزينها في مجلد معين فبدون هذه الأداة سيتوجب عليك استطلاع ذلك المجلد على فترات زمنية محددة – عادة باستخدام الـ Timer – ولكن هذه الأداة تسهل عليك هذا الأمر. وممكن أن تكون هذه الأداة مفيدة عندما تقوم بتخزين ملف بيانات في الذاكرة لتسهيل الوصول إليه بسرعة ولكنك تحتاج لإعادة تحميله في الذاكرة إذا قام برنامج آخر بتغيير محتوياته.تعريف التحكم FileSystemWatcher
يمكنك إنشاء التحكم FileSystemWatcher بإحدى طريقتين إما عن طريق الكود أو بسحبها من شريط الأدوات إلى النموذج من خلال مصمم النماذج ولا يوجد أي اختلاف في الأداء بينهما فيمكنك استخدام أي طريقة تفضلها وإنشاؤه عن طريق الكود يتم بسهولة
كود :
' Use WithEvents to be able to trap events from this object.
Dim WithEvents fsw As New FileSystemWatcher()
فالخاصية Path تحدد مسار المجلد الذي ترغب بمراقبته لاحظ أنه سيتم إعلامك بالتغييرات داخل المجلد وليس بالتغييرات على خصائصه
والخاصية IncludeSubdirectories يجب ضبطها إلى False إذا كنت ترغب بإعلامك بالتغييرات داخل ذلك المجلد فقط أو إلى True إذا كنت ترغب بمراقبة كامل لشجرة المجلد بحيث يكون جذرها هو المجلد المحدد بالخاصية Path
والخاصية Filter تمكنك من تحديد ما هي الملفات التي تهمك فاستخدام *.* يجعلك تراقب جميع الملفات بينما استخدام *.txt يجعلك تراقب الملفات التي تملك اللاحقة txt فقط والقيمة الافتراضية لهذه الخاصية هي Null وهي تطابق *.*
والخاصية NotifyFilter مرمزة على مستوى البت bit-coded بحيث يمكنك تحديد تشكيلة من واحد أو أكثر من قيم مرقمة enumerated كـ Attributes و CreationTime و DirectoryName و FileName و LastAccess و LastWrite و Security و Size و القيمة الافتراضية لها هي LastWrite Or FileName Or DirectoryName ففي هذه الحالة لن تتلقى تنبيهات عندما تتغير الخصائص
وإليك مثال عن كيفية تعريف تحكم FileSystemWatcher من أجل التغييرات في شجرة المجلد C:\Windows
كود :
Dim WithEvents fsw As New FileSystemWatcher()
…
fsw.Path = "c:\windows"
fsw.IncludeSubdirectories = True ' Watch subdirectories.
fsw.Filter = "*.dll" ' Watch only DLL files.
' Add attribute changes to the list of changes that can fire events.
fsw.NotifyFilter = fsw.NotifyFilter Or NotifyFilters.Attributes
' Enable event notification.
fsw.EnableRaisingEvents = True
بعد أن تكون قد عرفت هذا العنصر بصورة صحيحة ستحصل على التنبيهات فور حدوث أي شئ حيث يمكنك تفعيل ذلك بمعالجة الأحداث أو باستخدام الطريقة WaitForChange
وأبسط طريقة للحصول على التنبيهات من FileSystemWatcher هي بكتابة معالجات للأحداث الخاصة بهذا العنصر ولكن هذه الأحداث لن تنطلق حتى تقوم بضبط الخاصية EnableRaisingEvents إلى True و تستقبل الأحداث Created و Deleted و Changed البارامتر FileSystemEventArgs الذي يعرض خاصيتان هامتان Name اسم الملف الذي وقع عليه الحدث و FullPath مسار ذلك الملف الكامل
كود :
Private Sub fsw_Created(ByVal sender As Object, _
ByVal e As FileSystemEventArgs) Handles fsw.Created
Console.WriteLine("File created: {0}", e.FullPath)
End Sub
Private Sub fsw_Deleted(ByVal sender As Object, _
ByVal e As FileSystemEventArgs) Handles fsw.Deleted
Console.WriteLine("File deleted: {0}", e.FullPath)
End Sub
Private Sub fsw_Changed(ByVal sender As Object, _
ByVal e As FileSystemEventArgs) Handles fsw.Changed
Console.WriteLine("File changed: {0}", e.FullPath)
End Sub
كود :
Private Sub fsw_All(ByVal sender As Object, ByVal e As FileSystemEventArgs) _
Handles fsw.Changed, fsw.Created, fsw.Deleted
Console.WriteLine("File changed: {0} ({1})", e.FullPath, e.ChangeType)
End Sub
كود :
Private Sub fsw_Renamed(ByVal sender As Object, ByVal e As RenamedEventArgs) _
Handles fsw.Renamed
Console.WriteLine("File renamed: {0} => {1}", e.OldFullPath, e.FullPath)
End Sub
يطلق FileSystemWatcher حدث مستقل لكل حدث يقع على ملف ما فعلى سبيل المثال إذا حذفت 10 ملفات ستتلقى 10 أحداث بحيث يكون لكل ملف الحدث الخاص به وكذلك إن قمت بنقل 10 ملفات من مجلد لآخر ستتلقى 10 أحداث حذف و 10 أحداث إنشاء
الطريقة WaitForChanged
إذا كان برنامجك لا يقوم بعمل أي شئ سوى انتظار التغييرات في مجلد معين أو أنك تقوم بمراقبة تغييرات الملفات من مسار ثانوي Secondary Thread يمكنك كتابة كود أبسط وأكثر فاعلية باستخدام الطريقة WaitForChanged وهي متزامنة Synchronous أي أنها لا تعود حتى يحدث تغيير ما أو ينتهي الوقت المحدد timeout وعندما تعود هذه الطريقة يستقبل البرنامج النتيجة عبر التركيب WaitForChangedResult Structure الذي تمكنك خصائصه من تحديد فيما إذا انتهت المدة أو أن حدث ما قد وقع واسم الملف المتعلق بالحدث
كود :
' Create a *new* FileSystemWatcher component with values from
' the txtPath and txtFilter controls.
Dim tmpFsw As New FileSystemWatcher(txtPath.Text, txtFilter.Text)
' Wait max 10 seconds for any file event.
Dim res As WaitForChangedResult = tmpFsw.WaitForChanged(WatcherChangeTypes.All, 10000)
' Check whether the operation timed out.
If res.TimedOut Then
Console.WriteLine("10 seconds have elapsed without an event")
Else
Console.WriteLine("Event: {0} ({1}), res.Name, res.ChangeType.ToString())
End If
كود :
' Pause the application until the c:\temp\temp.dat file is deleted.
tmpFsw = New FileSystemWatcher("c:\temp", "temp.dat")
tmpFsw.WaitForChanged(WatcherChangeTypes.Deleted)
Buffer Overflows
كود :
Private Sub fsw_Error(ByVal sender As Object, ByVal e As ErrorEventArgs) _
Handles fsw.Error
Console.WriteLine("FileSystemWatcher error: {0}", e.GetException().Message)
End Sub
معالجة المشاكل
في الحالة الافتراضية فأحداث FileSystemWatcher يتم تنفيذها على مسار مأخوذ من بركة مسارات النظام System thread pool وبما أن تحكمات Windows Forms ليست أمنة للمسارات not thread safe لذلك يجب أن لا تحاول الوصول إلى أي تحكم أو حتى النموذج نفسه من داخل أحداث التحكم FileSystemWatcher وإن وجدت هذا التصرف غير مقبول فعليك تمرير تحكم Windows Forms للخاصية SynchronizingObject كالمثال
كود :
' Use the Form object as the synchronizing object.
fsw.SynchronizingObject = Me
وفيما يلي بعض الأفكار المفيدة عند التعامل مع التحكم FileSystemWatcher وبعض المشاكل التي قد تحتاج لحلها عندما تقوم باستخدامه
- يقوم التحكم بالبدء بإطلاق الأحداث عندما تكون الخاصية Path غير فارغة والخاصية EnableRaisingEvents مضبوطة إلى True كما يمكنك منعه من إطلاق الأحداث خلال طور التحميل للنموذج بتضمين أوامر التهيئة الخاصة بك بين العبارتين BeginInit و EndInit كما يفعل مصمم النماذج الخاص بفيجوال ستوديو
- في بعض الحالات قد تستقبل عدة أحدث إنشاء للملف اعتمادا على الطريقة التي يتم إنشاء الملف بها فمثلا عندما تقوم بإنشاء ملف باستخدام المفكرة Notepad ستلاحظ سلسلة من الأحداث Created و Deleted و Created و Changed
- التغيير في ملف يولد أيضا حدث إضافي في المجلد الأب أيضا لأن المجلد يحافظ على معلومات حول الملفات الموجودة داخله
- إذا كان المجلد المحدد كقيمة للخاصية Path تمت إعادة تسميته فإن التحكم FileSystemWatcher يستمر بالعمل بصورة صحيحة ولكن في هذه الحالة يستمر التحكم بإعادة الاسم القديم للمجلد وبالتالي قد تحصل على خطأ عند استخدامه وهذا يحدث بسبب أن التحكم يتعامل مع مقبض المجلد الذي لا يتغير بتغيير اسم المجلد
- إذا أنشأت مجلد ضمن المجلد الذي تتم مراقبته وكانت الخاصية IncludeSubdirectories مضبوطة على True فستتم مراقبة المجلد الجديد أيضا
- عندما يتم إنشاء ملف كبير ضمن المجلد فقد لا تستطيع قراءة كامل الملف مباشرة لأنه يكون ما يزال مملوكا من قبل العملية Process التي قامت بكتابة البيانات إلى ذلك الملف ويجب عليك حماية الكتابة إلى الملف الأصلي باستخدام حلقة Try فإن تم إطلاق خطأ يمكنك محاولة العملية بعد بضع ميلي ثانية أخرى
- عندما يقوم المستخدم بحذف ملف في مجلد فإن ملفا جديدا سيتم إنشاؤه في مجلد سلة المحذوفات RecycleBin