الفريق العربي للبرمجةأرشيف المنتديات · 2000 – 2023
نسخة أرشيفية للقراءة فقط — التسجيل والمشاركة مغلقان، والمحتوى محفوظ كما كان.

مراقبة نظام الملفات FileSystemWatcher

مغلق
بدأه محمد سامر أبو سلو في 25 أكتوبر 2006 · 3 رد · 983 مشاهدة · في Microsoft Visual Basic.NET
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

توفر لك الأداة FileSystemWatcher إمكانية مراقبة مجلد أو شجرة مجلدات بحيث تحصل على تنبيهات عندما يحصل أي شئ بداخلها فمثلا عندما يتم إنشاء أو حذف أو إعادة تسمية مجلد أو ملف أو عندما تتغير خصائص مجلد ما حيث تعتبر هذه الأداة ذات فائدة في العديد من الظروف فإذا كنت تقوم بعمل برنامج يقوم بتشفير الملفات آليا عندما يتم تخزينها في مجلد معين فبدون هذه الأداة سيتوجب عليك استطلاع ذلك المجلد على فترات زمنية محددة – عادة باستخدام الـ Timer – ولكن هذه الأداة تسهل عليك هذا الأمر. وممكن أن تكون هذه الأداة مفيدة عندما تقوم بتخزين ملف بيانات في الذاكرة لتسهيل الوصول إليه بسرعة ولكنك تحتاج لإعادة تحميله في الذاكرة إذا قام برنامج آخر بتغيير محتوياته.

تعريف التحكم FileSystemWatcher

يمكنك إنشاء التحكم FileSystemWatcher بإحدى طريقتين إما عن طريق الكود أو بسحبها من شريط الأدوات إلى النموذج من خلال مصمم النماذج ولا يوجد أي اختلاف في الأداء بينهما فيمكنك استخدام أي طريقة تفضلها وإنشاؤه عن طريق الكود يتم بسهولة

' Use WithEvents to be able to trap events from this object.
Dim WithEvents fsw As New FileSystemWatcher()

قبل استخدامك لهذا العنصر عليك أولا تعريف الخصائص Path و IncludeSubdirectories و Filter و NotifyFilter

فالخاصية 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

البارامتر FileSystemEventArgs يعرض أيضا خاصية ChangeType وهي خاصية مرقمة Enumerated حيث تخبرك بالحدث الذي وقع على الملف بحيث يمكنك استخدامها لعمل إجراء معالجة وحيد للأحداث الثلاثة السابقة

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

الحدث Changed لا يستقبل أية معلومات حول نوع التغيير الذي أطلق الحدث والحدث Renamed يستقبل البارامتر RenamedEventArgs الذي يعرض خاصيتان إضافيتان هما OldName الاسم القديم و OldFullPath المسار الكامل القديم

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 واحد يمكنك معالجة أحداثهم جميعا بنفس إجراء معالجة حدث واحد وعند ذلك يمكنك استخدام البارامتر الأول sender لمعرفة أي FileSystemWatcher أطلق الحدث.

يطلق 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

الطريقة WaitForChanged تراقب فقط التغييرات في المجلد المشار إليه وتتجاهل الخاصية IncludeSubDirectories ولهذا السبب فالتركيب WaitForChangedResult Structure يعيد حقل Name فقط ولا يعيد الحقل FullPath والبارامتر الأول الذي تقوم بتمريره إلى الطريقة WaitForChanged يمكنك من تحديد نوع العملية التي تريد اعتراضها

' 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

يجب عليك إدراك المشاكل المحتملة نتيجة انطلاق العديد من الأحداث خلال فترة قصيرة فالعنصر FileSystemWatcher يستخدم buffer داخلي ليتتبع أفعال نظام الملفات حتى لو كان البرنامج لا يستطيع تخديم تلك الأحداث بالسرعة الكافية وبالوضع الافتراضي يكون حجم الـ buffer هو 8KB ويمكنه تخزين حتى 160 حدث فكل حدث يأخذ 16 بايت إضافة لـ 2 بايت لكل محرف في اسم الملف وإن كنت تتوقع نشاطا أكثر فعليك زيادة حجم الـ buffer بضبط الخاصية InternalBufferSize إلى قيمة أكبر والحجم يجب أن يكون عددا صحيحا Integer مضروبا بحجم صفحة النظام ( 4KB في حالة ويندوز 2000 وما تلاه ) كما يمكنك استخدام الخاصية NotifyFilter لتحديد عدد عمليات التغيير التي تطلق الحدث Changed أو ضبط الخاصية IncludeSubdirectories إلى False إن كنت لا تحتاج لمراقبة شجرة المجلد كاملة ( يمكنك استخدام عدة عناصر FileSystemWatcher لمراقبة عدد من المجلدات إن كنت لا تحتاج لمراقبة الشجرة كاملة تحت مسار مجلد معين ) ولا يمكنك استخدام الخاصية Filter لمنع Buffer Overflowing لأنها تقوم بتصفيتها بعد أن يتم إضافتها لـ Buffer وعندما يحدث فيضان في الـ buffer سينطلق حدث خطأ

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

فإن لاحظت أن برنامجك يتلقى هذا الحدث فيجب عليك تغيير إستراتيجية معالجة الأحداث لديك فمثلا يمكنك تخزين الأحدث في صف queue ثم تخديمهم عبر مسار thread آخر

معالجة المشاكل

في الحالة الافتراضية فأحداث FileSystemWatcher يتم تنفيذها على مسار مأخوذ من بركة مسارات النظام System thread pool وبما أن تحكمات Windows Forms ليست أمنة للمسارات not thread safe لذلك يجب أن لا تحاول الوصول إلى أي تحكم أو حتى النموذج نفسه من داخل أحداث التحكم FileSystemWatcher وإن وجدت هذا التصرف غير مقبول فعليك تمرير تحكم Windows Forms للخاصية SynchronizingObject كالمثال

' Use the Form object as the synchronizing object.
fsw.SynchronizingObject = Me

فالكود السابق يتأكد من أن جميع الأحداث يتم تنفيذها بنفس المسار الذي يخدم النموذج نفسه وفي Visual Studio 2005 عندما تستخدم مصمم النماذج لإنشاء العنصر FileSystemWatcher يتم ضبط هذه الخاصية تلقائيا للنموذج الذي يضم التحكم

وفيما يلي بعض الأفكار المفيدة عند التعامل مع التحكم FileSystemWatcher وبعض المشاكل التي قد تحتاج لحلها عندما تقوم باستخدامه

- يقوم التحكم بالبدء بإطلاق الأحداث عندما تكون الخاصية Path غير فارغة والخاصية EnableRaisingEvents مضبوطة إلى True كما يمكنك منعه من إطلاق الأحداث خلال طور التحميل للنموذج بتضمين أوامر التهيئة الخاصة بك بين العبارتين BeginInit و EndInit كما يفعل مصمم النماذج الخاص بفيجوال ستوديو

- في بعض الحالات قد تستقبل عدة أحدث إنشاء للملف اعتمادا على الطريقة التي يتم إنشاء الملف بها فمثلا عندما تقوم بإنشاء ملف باستخدام المفكرة Notepad ستلاحظ سلسلة من الأحداث Created و Deleted و Created و Changed

- التغيير في ملف يولد أيضا حدث إضافي في المجلد الأب أيضا لأن المجلد يحافظ على معلومات حول الملفات الموجودة داخله

- إذا كان المجلد المحدد كقيمة للخاصية Path تمت إعادة تسميته فإن التحكم FileSystemWatcher يستمر بالعمل بصورة صحيحة ولكن في هذه الحالة يستمر التحكم بإعادة الاسم القديم للمجلد وبالتالي قد تحصل على خطأ عند استخدامه وهذا يحدث بسبب أن التحكم يتعامل مع مقبض المجلد الذي لا يتغير بتغيير اسم المجلد

- إذا أنشأت مجلد ضمن المجلد الذي تتم مراقبته وكانت الخاصية IncludeSubdirectories مضبوطة على True فستتم مراقبة المجلد الجديد أيضا

- عندما يتم إنشاء ملف كبير ضمن المجلد فقد لا تستطيع قراءة كامل الملف مباشرة لأنه يكون ما يزال مملوكا من قبل العملية Process التي قامت بكتابة البيانات إلى ذلك الملف ويجب عليك حماية الكتابة إلى الملف الأصلي باستخدام حلقة Try فإن تم إطلاق خطأ يمكنك محاولة العملية بعد بضع ميلي ثانية أخرى

- عندما يقوم المستخدم بحذف ملف في مجلد فإن ملفا جديدا سيتم إنشاؤه في مجلد سلة المحذوفات RecycleBin

مترجم للفائدة

تم تعديل هذه المشاركة بواسطة samerselo في 25 أكتوبر 2006 في 22:02

عن عائشة رضي الله عنها أن النبي صلى الله عليه وسلم قال: إن الله يحب إذا عمل أحدكم عملا أن يتقنه

نعيب زماننا والعيب فينا ... وما لزماننا عيب سوانا

ونهجو ذا الزمان بغير ذنب ... ولو نطق الزمان لنا هجانا

محمد سامر أبو سلو

#2

لا شكر على واجب أخي

أرجو أن يستفيد الجميع

عن عائشة رضي الله عنها أن النبي صلى الله عليه وسلم قال: إن الله يحب إذا عمل أحدكم عملا أن يتقنه

نعيب زماننا والعيب فينا ... وما لزماننا عيب سوانا

ونهجو ذا الزمان بغير ذنب ... ولو نطق الزمان لنا هجانا

محمد سامر أبو سلو

#4

كل عام وأنتم بخير ( بعد الزحمة )

معلومة مهمة جدا

بالتوفيق

اللهم اغفر لي و لوالدي و للمؤمنين يوم يقوم الحساب

لا إله إلا الله عدد ما كان و عدد ما يكون و عدد الحركات و السكون

هذا الموضوع مغلق.

مواضيع مشابهة