274. FileSystemWatcher

[נכתב ע”י ולרי פליסקין]

לפעמים אנחנו נדרשים לדעת על השינוי שהתרחש בקובץ או בתיקיה כלשהי.

הדרך הנאיבית - מימוש התכולה בצורה עצמאית.

ע”י שימוש במרכבים הבאים:

  1. Timer
  2. שמירת מצב הנוכחי של התיקייה
  3. שמירת נתוני metadata של התיקייה והקבצים המעניינים

למזלנו המקרה הזה מספיק נפוץ כדי שתהיה מחלקה מיוחדת בFramework שתטפל לנו בנושא: FileSystemWatcher

המחלקה יושבת בתוך הnamespace ששמו System.IO

היא מאפשרת לנו לקבל בדחיפה עדכונים על שינויים במבנה של התיקייה או קבצים שמעניינים אותנו.

תכולות עיקריות:

Eventים

Created/Renamed/Changed/Removed מתרחשים כאשר קובץ/תיקיית יעד שלנו השתנתה (בהתאם לשם הevent)

Properties

  • Path – נתיב לתיקיה שאנחנו רוצים לעקוב אחריה
  • NotifyFilter – איזה סוג שינויים מעניינים אותנו
  • Filter – באיזה סוגי קבצים מעניינים אותנו השינויים
  • EnableRaisingEvents – האם להתחיל האזנה לשינויים

Methods

  • WaitForChanged מתודה סינכרונית שנכנסת להמתנה עד שלא מתרחש שינוי המבוקש ביעד.

נציג כמה דוגמאות:

  • 1
    2
    3
    FileSystemWatcher myWatcher = new FileSystemWatcher(@"C:\test");
    var res = myWatcher.WaitForChanged(WatcherChangeTypes.Created);
    Console.WriteLine(res.Name);

כתוצאה מ3 השורות קוד האלה התוכנית שלנו תיתקע על השורה השנייה ותשתחרר רק לאחר היווצרותו של קובץ חדש בתיקיית"test" בכונן C. לאחר שניצור קובץ כלשהו בתיקיה הנ"ל נקבל במסך פלט של התוכנית את שם הקובץ שנוצר.

  • נעדכן טיפה את הדוגמא הראשונה:
1
2
3
FileSystemWatcher myWatcher = new FileSystemWatcher(@"C:\Test","*.log");
var res = myWatcher.WaitForChanged(WatcherChangeTypes.Created | WatcherChangeTypes.Renamed);
Console.WriteLine(res.Name);

ניצור קובץ טקסט חדש בתוך התיקייה ונקרא לו test.txt נראה שאין שום דבר בחלון הפלט של התוכנה שלנו והיא עדיין תקועה. זה קורה משום שכעט אנחנו משתמשים בoverload אחר של הctor של הFSW שמקבל גם מחרוזת פילטר לסינון סוגי הקבצים שמעניין אותנו לקבל את השינויים שלהם. אם נשנה את הקובץ שיצרנו לtext.log מיד נקבל תוצאה בחלון הפלט של התוכנה.

  • בדוגמא האחרונה נדגים שימוש בeventים של המחלקה שמאפשרים ריצה רגילה של התוכנית שלנו, ללא תקיעה סינכרונית בזמן ההמתנה לשינויים במערכת הקבצים:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
static void Main(string[] args)
{
//we are interested in changes in Test folder only on log files
FileSystemWatcher myWatcher = new FileSystemWatcher(@"C:\Test", "*.log");
// we are interested in file size changes only
myWatcher.NotifyFilter = NotifyFilters.Size;
//we want to get notifications on rename and changes only
myWatcher.Renamed += myWatcher_Renamed;
myWatcher.Changed += myWatcher_Changed;
//start observing the changes
myWatcher.EnableRaisingEvents = true;
Console.WriteLine("Waiting to changes");
Console.ReadKey();
}
static void myWatcher_Changed(object sender, FileSystemEventArgs e)
{
Console.WriteLine(string.Format("File was changed, Change type: {0}, file name: {1}", e.ChangeType, e.Name));
}
static void myWatcher_Renamed(object sender, RenamedEventArgs e)
{
Console.WriteLine(string.Format("File was renamed, old name: {0}, new name: {1}", e.OldName, e.Name));
}

כמו שאתם רואים, המחלקה מאוד שימושית וחושפת הרבה אופציות למשתמש. נזכיר עוד כמה נקודות חשובות

ניתן לעקוב אחרי שינויים בכונן רשת כי הpath מועבר בפורמט UNC.

כמה חסרונות:

  1. אי אפשר לקבל את השינוי עצמו בתוכן של הקובץ אלא רק הודעה שהקובץ השתנה.
  2. יש בעיה ידועה (שאולי כבר נפתרה) במימוש FileStream.Flush בWindows Vista ומעלה. המימוש של המתודה לא מעדכן נתוני metadata של הקובץ (הם מתעדכנים רק בקריאה לClose) ולכן לא נקבל עדכון על שינוי בקובץ דרך הFSW. זה לא קורה בגרסאות ווינדוס הקודמות והשינוי נבע מתוך שיקולי ביצועים בעבודה מול מערכת הקבצים.
  3. אם משתמשים בכמה מופעים של FSW על אותו נתיב רק אחד מהם יקבל את העדכון
  4. לא נועד לעקוב אחרי תיקיות/קבצים שעוברים שינויים בקצבים מאוד גדולים.

חג שמח וצפייה נעימה!

שתף