使用C#如何監控選定資料夾中檔案的變動情況?

mingupupup發表於2023-12-28

目錄✨

1、前言

2、效果

3、具體實現

​ 頁面設計

​ 全部程式碼

​ FileSystemWatcher的介紹

​ FileSystemWatcher的建構函式

​ FileSystemWatcher的屬性

​ FileSystemWatcher的事件

4、總結

前言✨

有時候我們會有監控電腦上某一個資料夾中檔案變動情況的需求,在本文中,我也會以一個具體的例子,說明在C#中如何使用FileSystemWatcher類來實現上述需求。

效果✨

檔案監控效果

image-20231227100851391

具體實現✨

如果你對C#如何監控選定資料夾中檔案的變動情況感興趣,可以繼續往下閱讀。

介面設計

為了更好的演示效果,我這裡winform的介面設計如下:

image-20231227101050127

很簡單,只有一個button與一個richtextbox,button用來指定被監控的檔案,richtextbox用來輸出一些資訊。

全部程式碼

namespace FileSystemWatcherDemo
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {

            // 建立一個 FolderBrowserDialog 例項
            FolderBrowserDialog folderBrowserDialog = new FolderBrowserDialog();

            // 設定對話方塊的標題
            folderBrowserDialog.Description = "選擇資料夾";

            // 如果使用者點選了“確定”按鈕
            if (folderBrowserDialog.ShowDialog() == DialogResult.OK)
            {
                richTextBox1.Text = "";
                // 獲取使用者選擇的資料夾路徑
                string selectedFolder = folderBrowserDialog.SelectedPath;

                // 提示被監控資料夾路徑
                richTextBox1.Text += $"被監控的資料夾為:{selectedFolder}\r\n";

                var watcher = new FileSystemWatcher($"{selectedFolder}");
               
                watcher.NotifyFilter = NotifyFilters.Attributes
                                | NotifyFilters.CreationTime
                                | NotifyFilters.DirectoryName
                                | NotifyFilters.FileName
                                | NotifyFilters.LastAccess
                                | NotifyFilters.LastWrite
                                | NotifyFilters.Security
                                | NotifyFilters.Size;

                watcher.Changed += OnChanged;
                watcher.Created += OnCreated;
                watcher.Deleted += OnDeleted;
                watcher.Renamed += OnRenamed;
                
                watcher.Filter = "*.txt";
                watcher.IncludeSubdirectories = true;
                watcher.EnableRaisingEvents = true;
            }
            else
            {
                MessageBox.Show("您本次沒有選擇資料夾!!!");
            }
          

           
   
        }

        private void AppendMessageToRichTextBox(string message)
        {
            // 在RichTextBox中新增提示資訊        
            richTextBox1.Invoke(new Action(() =>
            {
                richTextBox1.AppendText(message + Environment.NewLine);
            }));
        }

        private void OnChanged(object sender, FileSystemEventArgs e)
        {
            if (e.ChangeType != WatcherChangeTypes.Changed)
            {
                return;
            }
            AppendMessageToRichTextBox($"Changed: {e.FullPath}");
        }

        private void OnCreated(object sender, FileSystemEventArgs e)
        {
            string value = $"Created: {e.FullPath}";
            AppendMessageToRichTextBox($"Created: {e.FullPath}");
        }

        private  void OnDeleted(object sender, FileSystemEventArgs e)
        {
            AppendMessageToRichTextBox($"Deleted: {e.FullPath}");
        }

        private  void OnRenamed(object sender, RenamedEventArgs e)
        {       
            AppendMessageToRichTextBox($"Renamed:");
            AppendMessageToRichTextBox($"    Old: {e.OldFullPath}");
            AppendMessageToRichTextBox($"    New: {e.FullPath} ");           
        }
     
    }
}

FileSystemWatcher的介紹

看過以上程式碼,會發現核心就是FileSystemWatcher的使用。接下來我將介紹一下C#中的FileSystemWatcher類。

FileSystemWatcher是C#中的一個類,該類可以偵聽檔案系統更改通知,並在目錄或目錄中的檔案發生更改時引發事件。

FileSystemWatcher的建構函式

該類有三種建構函式,如下所示:

形式 含義
FileSystemWatcher() 初始化 FileSystemWatcher 類的新例項。
FileSystemWatcher(String) 初始化 FileSystemWatcher 類的新例項,給定要監視的目錄。
FileSystemWatcher(String, String) 初始化 FileSystemWatcher類的新例項,給定要監視的目錄和檔案型別。
 var watcher = new FileSystemWatcher($"{selectedFolder}");

本文中我選擇的就是第二種建構函式,指定要監視的目錄。

FileSystemWatcher的屬性

現在介紹一下在本示例中用到的FileSystemWatcher的屬性,如下所示:

名稱 型別 含義
EnableRaisingEvents bool 設定FileSystemWatcher是否有效
Filter string 設定一個要監控的檔案的格式
Filters Collection 設定多個要監控的檔案的格式
IncludeSubdirectories bool 獲取或設定一個值,該值指示是否應監視指定路徑中的子目錄
NotifyFilter NotifyFilters 獲取或設定要監視的更改的型別
Path string 獲取或設定要監視的目錄的路徑

現在來解釋下所用到的程式碼的含義:

watcher.Filter = "*.txt";

表示要監控的檔案為.txt格式。

 watcher.IncludeSubdirectories = true;

表示指定路徑中的子目錄也要監視。

 watcher.EnableRaisingEvents = true;

表示該物件可以觸發事件,也就是還有效。

 watcher.NotifyFilter = NotifyFilters.Attributes
                                | NotifyFilters.CreationTime
                                | NotifyFilters.DirectoryName
                                | NotifyFilters.FileName
                                | NotifyFilters.LastAccess
                                | NotifyFilters.LastWrite
                                | NotifyFilters.Security
                                | NotifyFilters.Size;

設定要監視的更改的型別。NotifyFilter屬性的型別為NotifyFilters列舉型別。

NotifyFilters列舉型別:

[System.Flags]
public enum NotifyFilters

指定要在檔案或資料夾中監視的更改。

此列舉支援其成員值的按位組合。

該列舉型別包含的值與含義如下所示:

名稱 含義
Attributes 檔案或資料夾的屬性
CreationTime 檔案或資料夾的建立時間
DirectoryName 目錄名
FileName 檔案的名稱
LastAccess 檔案或資料夾上一次開啟的日期
LastWrite 上一次向檔案或資料夾寫入內容的日期
Security 檔案或資料夾的安全設定
Size 檔案或資料夾的大小

在這裡使用了該列舉型別的按位組合表示這幾種更改的型別要受到監視。

FileSystemWatcher的事件

FileSystemWatcher中的事件如下:

名稱 含義
Changed 當更改指定 Path 中的檔案和目錄時發生
Created 當在指定Path 中建立檔案和目錄時發生
Deleted 刪除指定Path中的檔案或目錄時發生
Renamed 重新命名指定 Path中的檔案或目錄時發生
Error 當 FileSystemWatcher 的例項無法繼續監視更改或內部緩衝區溢位時發生
                watcher.Changed += OnChanged;
                watcher.Created += OnCreated;
                watcher.Deleted += OnDeleted;
                watcher.Renamed += OnRenamed;

在這裡我使用到了Changed、Created、Deleted和Renamed事件。

我將以Changed 事件為例,詳細解釋一下:

 watcher.Changed += OnChanged;

這行程式碼的含義。

我們檢視FileSystemWatcher的原始碼,Changed事件的程式碼如下所示:

/// <devdoc>
///    Occurs when a file or directory in the specified <see cref='System.IO.FileSystemWatcher.Path'/> is changed.
/// </devdoc>
public event FileSystemEventHandler? Changed
{
    add
    {
        _onChangedHandler += value;
    }
    remove
    {
        _onChangedHandler -= value;
    }
}

可知將值賦給了_onChangedHandler,我們再來檢視_onChangedHandler的定義:

 // Event handlers
 private FileSystemEventHandler? _onChangedHandler;

型別為FileSystemEventHandler?與Changed事件一致,再來看看FileSystemEventHandler?的定義:

 public delegate void FileSystemEventHandler(object sender, FileSystemEventArgs e);

發現是一個引數型別分別為object、FileSystemEventArgs返回值型別為空的委託型別。

object我們知道,那麼FileSystemEventArgs又是什麼呢?

檢視它的原始碼,擷取一部分,如下所示:

public class FileSystemEventArgs : EventArgs
{
     private readonly WatcherChangeTypes _changeType;
     private readonly string? _name;
     private readonly string _fullPath;
     /// <devdoc>
///    Gets one of the <see cref='System.IO.WatcherChangeTypes'/> values.
/// </devdoc>
public WatcherChangeTypes ChangeType
{
    get
    {
        return _changeType;
    }
}

/// <devdoc>
///    Gets the fully qualified path of the affected file or directory.
/// </devdoc>
public string FullPath
{
    get
    {
        return _fullPath;
    }
}


/// <devdoc>
///       Gets the name of the affected file or directory.
/// </devdoc>
public string? Name
{
    get
    {
        return _name;
    }
}
 }

發現FileSystemEventArgs繼承自EventArgs,而EventArgs表示包含事件資料的類的基類,因此可以明白FileSystemEventArgs表示為目錄事件:Changed, Created, Deleted提供資料的類。

FileSystemEventArgs提供三個資料分別為ChangeType、FullPath、Name。

那ChangeType是什麼呢?

檢視ChangeType的定義:

 //
 // 摘要:
 //     Changes that might occur to a file or directory.
 [Flags]
 public enum WatcherChangeTypes
 {
     //
     // 摘要:
     //     The creation of a file or folder.
     Created = 1,
     //
     // 摘要:
     //     The deletion of a file or folder.
     Deleted = 2,
     //
     // 摘要:
     //     The change of a file or folder. The types of changes include: changes to size,
     //     attributes, security settings, last write, and last access time.
     Changed = 4,
     //
     // 摘要:
     //     The renaming of a file or folder.
     Renamed = 8,
     //
     // 摘要:
     //     The creation, deletion, change, or renaming of a file or folder.
     All = 15
 }

是一個列舉型別,表示更改的型別。

現在回過頭來看:

watcher.Changed += OnChanged;

OnChanged方法如下:

  private void OnChanged(object sender, FileSystemEventArgs e)
  {
      if (e.ChangeType != WatcherChangeTypes.Changed)
      {
          return;
      }
      AppendMessageToRichTextBox($"Changed: {e.FullPath}");
  }

為什麼可以將OnChanged方法訂閱到watcher.Changed事件上呢?

因為OnChanged方法與watcher.Changed事件中的委託型別FileSystemEventHandler的返回型別和簽名是相同的。

OnChanged方法的返回型別與簽名如下:

 private void OnChanged(object sender, FileSystemEventArgs e)

FileSystemEventHandler委託型別的定義如下:

 public delegate void FileSystemEventHandler(object sender, FileSystemEventArgs e);

現在已經理解了訂閱事件,那麼什麼時候觸發事件呢?

檢視FileSystemWatcher的部分原始碼:

 /// <devdoc>
 ///    Raises the <see cref='System.IO.FileSystemWatcher.Changed'/> event.
 /// </devdoc>
 protected void OnChanged(FileSystemEventArgs e)
 {
     InvokeOn(e, _onChangedHandler);
 }
 private void InvokeOn(FileSystemEventArgs e, FileSystemEventHandler? handler)
 {
     if (handler != null)
     {
         ISynchronizeInvoke? syncObj = SynchronizingObject;
         if (syncObj != null && syncObj.InvokeRequired)
             syncObj.BeginInvoke(handler, new object[] { this, e });
         else
             handler(this, e);
     }
 }

當發生相應的改變時,就會呼叫FileSystemWatcher類的OnChanged方法,從而觸發事件。

總結✨

本文透過一個例項,介紹瞭如何透過C#中的FileSystemWatcher類實現監控選定的資料夾,希望對你有所幫助。

相關文章