顯示具有 C# 標籤的文章。 顯示所有文章
顯示具有 C# 標籤的文章。 顯示所有文章

2009年6月5日 星期五

監控檔案系統-FileSystemWatcher

這是本期PCADV上的一篇文章,說為了防止木馬,可以寫一個監控檔案是否有更改系統
他是用VB當範例,正巧我很久沒寫C#了,想說就用C#寫個簡單的版本來玩

下面是寫好的範例

跟PCADV上的不同,我簡化了不少功能

要做到檔案系統監控,.NET平台有提供FileSystemWatcher這個物件來替我們簡單辦到,他是在System.IO之下

他有幾個比較重要的屬性
  1. Path:設定或得到監控的目錄
  2. EnableRaisingEvents:開始或停止監控
  3. IncludeSubdirectories:是否監控子目錄


之後比較重要的幾個事件
  1. Created:檔案或目錄被創造
  2. Deleted:檔案或目錄被刪除
  3. Renamed:檔案或目錄被重新命名
  4. Changed:檔案或目錄被更動

這邊比較值的一提的是,我直接用

FileSystemWatcher fsw=new FileSystemWatcher();
fsw.Created += new FileSystemEventHandler(fsw_Created);//指派事件監聽
....
void fsw_Created(object sender, FileSystemEventArgs e)
{
this.textbox1.Text+=e.FullPath + " 檔案被創造";
}


會丟出InvalidOperationException 這樣的例外,會發生是因為企圖對Windows Form 的控制項使用不同執行緒來控制,MSDN有提供解套方法
http://msdn.microsoft.com/zh-tw/library/ms171728.aspx

可以使用Form的Invoke函式去發起一個委託,來達到安全執行緒的要求
簡單的範例

delegate void SetTextCallback(string text);//宣告一個委託的函式
SetTextCallback d;
....
public Form1()
{
......
fsw = new FileSystemWatcher();
fsw.Created += new FileSystemEventHandler(fsw_Created);
fsw.Deleted += new FileSystemEventHandler(fsw_Deleted);
d = new SetTextCallback(setText);//設定委託函式
}
...
private void setText(string text)
{
this.listView1.Items.Add(new ListViewItem(text));
//被委託函式實際要做的內容,在此我用ListView取代TextBox

}
...
void fsw_Created(object sender, FileSystemEventArgs e)
{
string currentMessage = e.FullPath + " 檔案被創造";
this.Invoke(d, new object[] { currentMessage });//要求委託函式

}


-----------------
這邊題外話
Eclipse用久了,他都會自動幫我import要用的函式庫,就算他沒幫我import
我也可以Ctrl+Shift+M去自動import
Visual Studio沒了這動作熊熊不習慣,就稍微找了一下有沒有類似的功能
就找到了類似的東西

C#自動using的方法
首先在不知道要using什麼類別下按滑鼠右鍵(在此我用Thread),之後選"解析",就可以看到要using的東西了

2009年2月10日 星期二

C#的事件指派


namespace ConsoleTest2008
{
public delegate void TestEvent(int myX);
class AT {


public AT()
{
_x = 100;
_y = 200;
}
//解構式測試
~AT() {
Console.WriteLine("AT is Die");
}
private int _x;
private int _y;
public event TestEvent isLarge;

public int Attr {

get {
return _x;
}
set
{
if (value < 0)
{
_x = 0;
}
else
{
if (value > 5)
{
isLarge(value);
}
_x = value;
}
}
}
}
class Program
{

static void Main(string[] args)
{

AT at = new AT();
Console.WriteLine("事件測試");
at.isLarge+=new TestEvent(at_isLarge);
at.Attr = 9;
GC.Collect();
/* Ctrl+F5 編譯時不會程式自動結束*/

}
static void at_isLarge(int _x)
{
Console.WriteLine("X:{0}太大", _x);
}
}


C#事件指派幾個要點

  • 宣告委託型態


    delegate void TestEvent(int myX);
    透過delegate 宣告事件處裡函式的基本型態
    之後的事件指派函式必須長的委託者長的一樣

  • 宣告事件


    public event TestEvent isLarge;
    透過event宣告事件名稱跟委託者型態
    上面程式代表事件 isLarge必須給樣式為TestEvent的人處裡
    制於事件何時發生必須透過物件程式自己判斷

    if (value > 5)
    {
    isLarge(value);
    }

    如上 ,當value大於5時 event就會被觸發
    事件可以當函數直接呼叫,但是參數要傳對

  • 事件委託


    上面宣告好之後就開始正式委託

    at.isLarge+=new TestEvent(at_isLarge);
    at.Attr = 9;

    物件at將isLarge事件委託給at_isLarge處裡


  • C#事件的委託很像C++函數指標,就是把函數當成變數來使用
    可以把delegate看成一種宣告函數指標
    可以用於很多方面

    delegate bool Compare(int a,int b);
    .......
    bool isSmall(int a,int b){...}
    bool isBig(int a,int b){...}
    Compare cmp=new Compare(isSmall);//將cmp指向函式isSmall
    swap(cmp);
    cmp==new Compare(isBig);//將cmp指向函式isBig
    swap(cmp);
    ....
    void swap(Compare cmp){...}


    藉此可達成另一種多型的應用

    C# 函式 ref out getter setter

    C#函式的參數傳遞有分三種 call By Value,call By Refeance,Output parameter
    第一種就是最原始的參數傳遞,也就是函式運作不改變
    call By Value範例
    int swap(a,b){....}
    int x,y;
    x=1;
    y=2;
    ......
    swap(x,y);


    上面範例 a,b,x,y都是使用不同記憶體 x,y的值不會被改變

    第二種是參數跟變數共用記憶體 變數會被函式影響
    call By Refeance範例
    int swap(ref a,ref b){....}
    int x,y;
    x=1;
    y=2;
    ......
    swap(ref x,ref y);


    上面範例 a跟x是同一份記憶體 b跟y是同一份記憶體
    x,y會被函式swap改變

    第三種就跟call By Refeance很像
    變數跟參數共用記憶體,但是變數不需要指派初始值
    變數的值由函式賦予
    int setValue(out a,out b){....}
    int x,y;
    ......
    setValue(out x,out y);




    再來介紹setter跟getter的語法

    class AT {


    public AT()
    {
    _x = 100;
    _y = 200;
    }
    private int _x;
    private int _y;
    /*getter setter屬性封裝測試*/
    public int Attr {

    get {
    return _x;
    }
    set
    {
    if (value < 0)
    {
    _x = 0;
    }
    else
    {
    _x = value;
    }
    }
    }
    /*唯獨屬性測試*/
    public int ReadOnly
    {
    get {
    return _y;
    }
    /*要建立唯獨屬性 就是只設立get*/
    /*要建立唯寫屬性 就是只設立set*/
    /*如果唯獨嘗試設值會編譯不過*/

    }

    }